diff --git a/CMakeLists.txt b/CMakeLists.txt index a2d05068d5..1326335df6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,7 @@ option(ENABLE_CHANNELTX_MOD802.15.4 "Enable channeltx mod802.15.4 plugin" ON) option(ENABLE_CHANNELTX_REMOTESOURCE "Enable channeltx remotesource plugin" ON) option(ENABLE_CHANNELTX_FILESOURCE "Enable channeltx filesource plugin" ON) option(ENABLE_CHANNELTX_MODRTTY "Enable channeltx modrtty plugin" ON) +option(ENABLE_CHANNELTX_MODPSK31 "Enable channeltx modpsk31 plugin" ON) # Channel MIMO enablers option(ENABLE_CHANNELMIMO "Enable channelmimo plugins" ON) diff --git a/doc/img/PSK31Mod_plugin.png b/doc/img/PSK31Mod_plugin.png new file mode 100644 index 0000000000..52be434967 Binary files /dev/null and b/doc/img/PSK31Mod_plugin.png differ diff --git a/plugins/channelrx/demodrtty/rttydemodgui.cpp b/plugins/channelrx/demodrtty/rttydemodgui.cpp index 5945a13040..2305079ef3 100644 --- a/plugins/channelrx/demodrtty/rttydemodgui.cpp +++ b/plugins/channelrx/demodrtty/rttydemodgui.cpp @@ -307,12 +307,19 @@ void RttyDemodGUI::on_spaceHigh_clicked(bool checked) m_settings.m_spaceHigh = checked; if (checked) { ui->spaceHigh->setText("M-S"); - } else { + } + else { ui->spaceHigh->setText("S-M"); } applySettings(); } +void RttyDemodGUI::on_unshiftOnSpace_clicked(bool checked) +{ + m_settings.m_unshiftOnSpace = checked; + applySettings(); +} + void RttyDemodGUI::on_clearTable_clicked() { ui->text->clear(); @@ -571,6 +578,7 @@ void RttyDemodGUI::displaySettings() } else { ui->spaceHigh->setText("S-M"); } + ui->unshiftOnSpace->setChecked(m_settings.m_unshiftOnSpace); updateIndexLabel(); @@ -657,6 +665,7 @@ void RttyDemodGUI::makeUIConnections() QObject::connect(ui->atc, &QCheckBox::clicked, this, &RttyDemodGUI::on_atc_clicked); QObject::connect(ui->endian, &QCheckBox::clicked, this, &RttyDemodGUI::on_endian_clicked); QObject::connect(ui->spaceHigh, &QCheckBox::clicked, this, &RttyDemodGUI::on_spaceHigh_clicked); + QObject::connect(ui->unshiftOnSpace, &QCheckBox::clicked, this, &RttyDemodGUI::on_unshiftOnSpace_clicked); QObject::connect(ui->clearTable, &QPushButton::clicked, this, &RttyDemodGUI::on_clearTable_clicked); QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &RttyDemodGUI::on_udpEnabled_clicked); QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &RttyDemodGUI::on_udpAddress_editingFinished); diff --git a/plugins/channelrx/demodrtty/rttydemodgui.h b/plugins/channelrx/demodrtty/rttydemodgui.h index 7d5723a2e5..7d8c8703c8 100644 --- a/plugins/channelrx/demodrtty/rttydemodgui.h +++ b/plugins/channelrx/demodrtty/rttydemodgui.h @@ -112,6 +112,7 @@ private slots: void on_atc_clicked(bool checked); void on_endian_clicked(bool checked); void on_spaceHigh_clicked(bool checked); + void on_unshiftOnSpace_clicked(bool checked); void on_clearTable_clicked(); void on_udpEnabled_clicked(bool checked); void on_udpAddress_editingFinished(); diff --git a/plugins/channelrx/demodrtty/rttydemodsettings.cpp b/plugins/channelrx/demodrtty/rttydemodsettings.cpp index ab55bfeefa..4b69af70c6 100644 --- a/plugins/channelrx/demodrtty/rttydemodsettings.cpp +++ b/plugins/channelrx/demodrtty/rttydemodsettings.cpp @@ -42,6 +42,7 @@ void RttyDemodSettings::resetToDefaults() m_udpPort = 9999; m_characterSet = Baudot::ITA2; m_suppressCRLF = false; + m_unshiftOnSpace = false; m_filter = LOWPASS; m_atc = true; m_msbFirst = false; diff --git a/plugins/channeltx/CMakeLists.txt b/plugins/channeltx/CMakeLists.txt index bb54edddbd..1a20b339a8 100644 --- a/plugins/channeltx/CMakeLists.txt +++ b/plugins/channeltx/CMakeLists.txt @@ -1,5 +1,9 @@ project(mod) +if (ENABLE_CHANNELTX_MODPSK31) + add_subdirectory(modpsk31) +endif() + if (ENABLE_CHANNELTX_MODRTTY) add_subdirectory(modrtty) endif() diff --git a/plugins/channeltx/modpsk31/CMakeLists.txt b/plugins/channeltx/modpsk31/CMakeLists.txt new file mode 100644 index 0000000000..eb52568005 --- /dev/null +++ b/plugins/channeltx/modpsk31/CMakeLists.txt @@ -0,0 +1,69 @@ +project(modpsk31) + +set(modpsk31_SOURCES + psk31mod.cpp + psk31modbaseband.cpp + psk31modsource.cpp + psk31modplugin.cpp + psk31modsettings.cpp + psk31modwebapiadapter.cpp +) + +set(modpsk31_HEADERS + psk31mod.h + psk31modbaseband.h + psk31modsource.h + psk31modplugin.h + psk31modsettings.h + psk31modwebapiadapter.h +) + +include_directories( + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client +) + +if(NOT SERVER_MODE) + set(modpsk31_SOURCES + ${modpsk31_SOURCES} + psk31modgui.cpp + psk31modgui.ui + psk31modrepeatdialog.cpp + psk31modrepeatdialog.ui + psk31modtxsettingsdialog.cpp + psk31modtxsettingsdialog.ui + ) + set(modpsk31_HEADERS + ${modpsk31_HEADERS} + psk31modgui.h + psk31modrepeatdialog.h + psk31modtxsettingsdialog.h + ) + set(TARGET_NAME modpsk31) + set(TARGET_LIB "Qt::Widgets") + set(TARGET_LIB_GUI "sdrgui") + set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) +else() + set(TARGET_NAME modpsk31srv) + set(TARGET_LIB "") + set(TARGET_LIB_GUI "") + set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR}) +endif() + +add_library(${TARGET_NAME} SHARED + ${modpsk31_SOURCES} +) + +target_link_libraries(${TARGET_NAME} + Qt::Core + ${TARGET_LIB} + sdrbase + ${TARGET_LIB_GUI} + swagger +) + +install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) + +# Install debug symbols +if (WIN32) + install(FILES $ CONFIGURATIONS Debug RelWithDebInfo DESTINATION ${INSTALL_FOLDER} ) +endif() diff --git a/plugins/channeltx/modpsk31/psk31mod.cpp b/plugins/channeltx/modpsk31/psk31mod.cpp new file mode 100644 index 0000000000..5b733156dd --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31mod.cpp @@ -0,0 +1,864 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 +#include +#include + +#include "SWGChannelSettings.h" +#include "SWGWorkspaceInfo.h" +#include "SWGChannelReport.h" +#include "SWGChannelActions.h" +#include "SWGPSK31ModReport.h" +#include "SWGPSK31ModActions.h" + +#include +#include +#include + +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "device/deviceapi.h" +#include "feature/feature.h" +#include "util/db.h" +#include "util/crc.h" +#include "maincore.h" + +#include "psk31modbaseband.h" +#include "psk31mod.h" + +MESSAGE_CLASS_DEFINITION(PSK31::MsgConfigurePSK31, Message) +MESSAGE_CLASS_DEFINITION(PSK31::MsgTx, Message) +MESSAGE_CLASS_DEFINITION(PSK31::MsgReportTx, Message) +MESSAGE_CLASS_DEFINITION(PSK31::MsgTXText, Message) + +const char* const PSK31::m_channelIdURI = "sdrangel.channeltx.modpsk31"; +const char* const PSK31::m_channelId = "PSK31Mod"; + +PSK31::PSK31(DeviceAPI *deviceAPI) : + ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSource), + m_deviceAPI(deviceAPI), + m_spectrumVis(SDR_TX_SCALEF), + m_sampleRate(48000), + m_udpSocket(nullptr) +{ + setObjectName(m_channelId); + + m_thread = new QThread(this); + m_basebandSource = new PSK31Baseband(); + m_basebandSource->setSpectrumSampleSink(&m_spectrumVis); + m_basebandSource->setChannel(this); + m_basebandSource->moveToThread(m_thread); + + applySettings(m_settings, true); + + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSourceAPI(this); + + m_networkManager = new QNetworkAccessManager(); + QObject::connect( + m_networkManager, + &QNetworkAccessManager::finished, + this, + &PSK31::networkManagerFinished + ); +} + +PSK31::~PSK31() +{ + closeUDP(); + QObject::connect( + m_networkManager, + &QNetworkAccessManager::finished, + this, + &PSK31::networkManagerFinished + ); + delete m_networkManager; + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + delete m_basebandSource; + delete m_thread; +} + +void PSK31::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSource(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + +void PSK31::start() +{ + qDebug("PSK31::start"); + m_basebandSource->reset(); + m_thread->start(); +} + +void PSK31::stop() +{ + qDebug("PSK31::stop"); + m_thread->exit(); + m_thread->wait(); +} + +void PSK31::pull(SampleVector::iterator& begin, unsigned int nbSamples) +{ + m_basebandSource->pull(begin, nbSamples); +} + +bool PSK31::handleMessage(const Message& cmd) +{ + if (MsgConfigurePSK31::match(cmd)) + { + MsgConfigurePSK31& cfg = (MsgConfigurePSK31&) cmd; + qDebug() << "PSK31::handleMessage: MsgConfigurePSK31"; + + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (MsgTx::match(cmd)) + { + MsgTx* msg = new MsgTx((const MsgTx&)cmd); + m_basebandSource->getInputMessageQueue()->push(msg); + + return true; + } + else if (MsgTXText::match(cmd)) + { + MsgTXText* msg = new MsgTXText((const MsgTXText&)cmd); + m_basebandSource->getInputMessageQueue()->push(msg); + + return true; + } + else if (DSPSignalNotification::match(cmd)) + { + // Forward to the source + DSPSignalNotification& notif = (DSPSignalNotification&) cmd; + DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy + qDebug() << "PSK31::handleMessage: DSPSignalNotification"; + m_basebandSource->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } + + return true; + } + else if (MainCore::MsgChannelDemodQuery::match(cmd)) + { + qDebug() << "PSK31::handleMessage: MsgChannelDemodQuery"; + sendSampleRateToDemodAnalyzer(); + + return true; + } + else + { + return false; + } +} + +void PSK31::setCenterFrequency(qint64 frequency) +{ + PSK31Settings settings = m_settings; + settings.m_inputFrequencyOffset = frequency; + applySettings(settings, false); + + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigurePSK31 *msgToGUI = MsgConfigurePSK31::create(settings, false); + m_guiMessageQueue->push(msgToGUI); + } +} + +void PSK31::applySettings(const PSK31Settings& settings, bool force) +{ + qDebug() << "PSK31::applySettings:" + << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset + << " m_baud: " << settings.m_baud + << " m_rfBandwidth: " << settings.m_rfBandwidth + << " m_gain: " << settings.m_gain + << " m_channelMute: " << settings.m_channelMute + << " m_repeat: " << settings.m_repeat + << " m_repeatCount: " << settings.m_repeatCount + << " m_text: " << settings.m_text + << " m_prefixCRLF: " << settings.m_prefixCRLF + << " m_postfixCRLF: " << settings.m_postfixCRLF + << " m_useReverseAPI: " << settings.m_useReverseAPI + << " m_reverseAPIAddress: " << settings.m_reverseAPIAddress + << " m_reverseAPIAddress: " << settings.m_reverseAPIPort + << " m_reverseAPIDeviceIndex: " << settings.m_reverseAPIDeviceIndex + << " m_reverseAPIChannelIndex: " << settings.m_reverseAPIChannelIndex + << " force: " << force; + + QList reverseAPIKeys; + + if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) { + reverseAPIKeys.append("inputFrequencyOffset"); + } + + if ((settings.m_baud != m_settings.m_baud) || force) { + reverseAPIKeys.append("baud"); + } + + if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) { + reverseAPIKeys.append("rfBandwidth"); + } + + if ((settings.m_gain != m_settings.m_gain) || force) { + reverseAPIKeys.append("gain"); + } + + if ((settings.m_channelMute != m_settings.m_channelMute) || force) { + reverseAPIKeys.append("channelMute"); + } + + if ((settings.m_repeat != m_settings.m_repeat) || force) { + reverseAPIKeys.append("repeat"); + } + + if ((settings.m_repeatCount != m_settings.m_repeatCount) || force) { + reverseAPIKeys.append("repeatCount"); + } + + if ((settings.m_lpfTaps != m_settings.m_lpfTaps) || force) { + reverseAPIKeys.append("lpfTaps"); + } + + if ((settings.m_rfNoise != m_settings.m_rfNoise) || force) { + reverseAPIKeys.append("rfNoise"); + } + + if ((settings.m_text != m_settings.m_text) || force) { + reverseAPIKeys.append("text"); + } + + if ((settings.m_beta != m_settings.m_beta) || force) { + reverseAPIKeys.append("beta"); + } + + if ((settings.m_symbolSpan != m_settings.m_symbolSpan) || force) { + reverseAPIKeys.append("symbolSpan"); + } + + if ((settings.m_prefixCRLF != m_settings.m_prefixCRLF) || force) { + reverseAPIKeys.append("prefixCRLF"); + } + + if ((settings.m_postfixCRLF != m_settings.m_postfixCRLF) || force) { + reverseAPIKeys.append("postfixCRLF"); + } + + if ((settings.m_udpEnabled != m_settings.m_udpEnabled) || force) { + reverseAPIKeys.append("udpEnabled"); + } + + if ((settings.m_udpAddress != m_settings.m_udpAddress) || force) { + reverseAPIKeys.append("udpAddress"); + } + + if ((settings.m_udpPort != m_settings.m_udpPort) || force) { + reverseAPIKeys.append("udpPort"); + } + + if ( (settings.m_udpEnabled != m_settings.m_udpEnabled) + || (settings.m_udpAddress != m_settings.m_udpAddress) + || (settings.m_udpPort != m_settings.m_udpPort) + || force) + { + if (settings.m_udpEnabled) + openUDP(settings); + else + closeUDP(); + } + + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSourceAPI(this); + m_deviceAPI->removeChannelSource(this, m_settings.m_streamIndex); + m_deviceAPI->addChannelSource(this, settings.m_streamIndex); + m_deviceAPI->addChannelSourceAPI(this); + } + + reverseAPIKeys.append("streamIndex"); + } + + PSK31Baseband::MsgConfigurePSK31Baseband *msg = PSK31Baseband::MsgConfigurePSK31Baseband::create(settings, force); + m_basebandSource->getInputMessageQueue()->push(msg); + + if (settings.m_useReverseAPI) + { + 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) || + (m_settings.m_reverseAPIChannelIndex != settings.m_reverseAPIChannelIndex); + webapiReverseSendSettings(reverseAPIKeys, settings, fullUpdate || force); + } + + QList pipes; + MainCore::instance()->getMessagePipes().getMessagePipes(this, "settings", pipes); + + if (pipes.size() > 0) { + sendChannelSettings(pipes, reverseAPIKeys, settings, force); + } + + m_settings = settings; +} + +QByteArray PSK31::serialize() const +{ + return m_settings.serialize(); +} + +bool PSK31::deserialize(const QByteArray& data) +{ + bool success = true; + + if (!m_settings.deserialize(data)) + { + m_settings.resetToDefaults(); + success = false; + } + + MsgConfigurePSK31 *msg = MsgConfigurePSK31::create(m_settings, true); + m_inputMessageQueue.push(msg); + + return success; +} + +void PSK31::sendSampleRateToDemodAnalyzer() +{ + QList pipes; + MainCore::instance()->getMessagePipes().getMessagePipes(this, "reportdemod", pipes); + + if (pipes.size() > 0) + { + for (const auto& pipe : pipes) + { + MessageQueue* messageQueue = qobject_cast(pipe->m_element); + MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create( + this, + getSourceChannelSampleRate() + ); + messageQueue->push(msg); + } + } +} + +int PSK31::webapiSettingsGet( + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setPsk31ModSettings(new SWGSDRangel::SWGPSK31ModSettings()); + response.getPsk31ModSettings()->init(); + webapiFormatChannelSettings(response, m_settings); + + return 200; +} + +int PSK31::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + +int PSK31::webapiSettingsPutPatch( + bool force, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + PSK31Settings settings = m_settings; + webapiUpdateChannelSettings(settings, channelSettingsKeys, response); + + MsgConfigurePSK31 *msg = MsgConfigurePSK31::create(settings, force); + m_inputMessageQueue.push(msg); + + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigurePSK31 *msgToGUI = MsgConfigurePSK31::create(settings, force); + m_guiMessageQueue->push(msgToGUI); + } + + webapiFormatChannelSettings(response, settings); + + return 200; +} + +void PSK31::webapiUpdateChannelSettings( + PSK31Settings& settings, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response) +{ + if (channelSettingsKeys.contains("inputFrequencyOffset")) { + settings.m_inputFrequencyOffset = response.getPsk31ModSettings()->getInputFrequencyOffset(); + } + if (channelSettingsKeys.contains("rfBandwidth")) { + settings.m_rfBandwidth = response.getPsk31ModSettings()->getRfBandwidth(); + } + if (channelSettingsKeys.contains("gain")) { + settings.m_gain = response.getPsk31ModSettings()->getGain(); + } + if (channelSettingsKeys.contains("channelMute")) { + settings.m_channelMute = response.getPsk31ModSettings()->getChannelMute() != 0; + } + if (channelSettingsKeys.contains("repeat")) { + settings.m_repeat = response.getPsk31ModSettings()->getRepeat() != 0; + } + if (channelSettingsKeys.contains("repeatCount")) { + settings.m_repeatCount = response.getPsk31ModSettings()->getRepeatCount(); + } + if (channelSettingsKeys.contains("lpfTaps")) { + settings.m_lpfTaps = response.getPsk31ModSettings()->getLpfTaps(); + } + if (channelSettingsKeys.contains("rfNoise")) { + settings.m_rfNoise = response.getPsk31ModSettings()->getRfNoise() != 0; + } + if (channelSettingsKeys.contains("text")) { + settings.m_text = *response.getPsk31ModSettings()->getText(); + } + if (channelSettingsKeys.contains("beta")) { + settings.m_beta = response.getPsk31ModSettings()->getBeta(); + } + if (channelSettingsKeys.contains("symbolSpan")) { + settings.m_symbolSpan = response.getPsk31ModSettings()->getSymbolSpan(); + } + if (channelSettingsKeys.contains("prefixCRLF")) { + settings.m_prefixCRLF = response.getPsk31ModSettings()->getPrefixCrlf(); + } + if (channelSettingsKeys.contains("postfixCRLF")) { + settings.m_postfixCRLF = response.getPsk31ModSettings()->getPostfixCrlf(); + } + if (channelSettingsKeys.contains("rgbColor")) { + settings.m_rgbColor = response.getPsk31ModSettings()->getRgbColor(); + } + if (channelSettingsKeys.contains("title")) { + settings.m_title = *response.getPsk31ModSettings()->getTitle(); + } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getPsk31ModSettings()->getStreamIndex(); + } + if (channelSettingsKeys.contains("useReverseAPI")) { + settings.m_useReverseAPI = response.getPsk31ModSettings()->getUseReverseApi() != 0; + } + if (channelSettingsKeys.contains("reverseAPIAddress")) { + settings.m_reverseAPIAddress = *response.getPsk31ModSettings()->getReverseApiAddress(); + } + if (channelSettingsKeys.contains("reverseAPIPort")) { + settings.m_reverseAPIPort = response.getPsk31ModSettings()->getReverseApiPort(); + } + if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) { + settings.m_reverseAPIDeviceIndex = response.getPsk31ModSettings()->getReverseApiDeviceIndex(); + } + if (channelSettingsKeys.contains("reverseAPIChannelIndex")) { + settings.m_reverseAPIChannelIndex = response.getPsk31ModSettings()->getReverseApiChannelIndex(); + } + if (channelSettingsKeys.contains("udpEnabled")) { + settings.m_udpEnabled = response.getPsk31ModSettings()->getUdpEnabled(); + } + if (channelSettingsKeys.contains("udpAddress")) { + settings.m_udpAddress = *response.getPsk31ModSettings()->getUdpAddress(); + } + if (channelSettingsKeys.contains("udpPort")) { + settings.m_udpPort = response.getPsk31ModSettings()->getUdpPort(); + } + if (settings.m_channelMarker && channelSettingsKeys.contains("channelMarker")) { + settings.m_channelMarker->updateFrom(channelSettingsKeys, response.getPsk31ModSettings()->getChannelMarker()); + } + if (settings.m_rollupState && channelSettingsKeys.contains("rollupState")) { + settings.m_rollupState->updateFrom(channelSettingsKeys, response.getPsk31ModSettings()->getRollupState()); + } +} + +int PSK31::webapiReportGet( + SWGSDRangel::SWGChannelReport& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setPsk31ModReport(new SWGSDRangel::SWGPSK31ModReport()); + response.getPsk31ModReport()->init(); + webapiFormatChannelReport(response); + return 200; +} + +int PSK31::webapiActionsPost( + const QStringList& channelActionsKeys, + SWGSDRangel::SWGChannelActions& query, + QString& errorMessage) +{ + SWGSDRangel::SWGPSK31ModActions *swgPSK31Actions = query.getPsk31ModActions(); + + if (swgPSK31Actions) + { + if (channelActionsKeys.contains("tx")) + { + if (swgPSK31Actions->getTx() != 0) + { + if (channelActionsKeys.contains("payload") + && (swgPSK31Actions->getPayload()->getText())) + { + MsgTXText *msg = MsgTXText::create( + *swgPSK31Actions->getPayload()->getText() + ); + m_basebandSource->getInputMessageQueue()->push(msg); + } + else + { + MsgTx *msg = MsgTx::create(); + m_basebandSource->getInputMessageQueue()->push(msg); + } + + return 202; + } + else + { + errorMessage = "Must contain tx action"; + return 400; + } + } + else + { + errorMessage = "Unknown PSK31Mod action"; + return 400; + } + } + else + { + errorMessage = "Missing PSK31ModActions in query"; + return 400; + } + return 0; +} + +void PSK31::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const PSK31Settings& settings) +{ + response.getPsk31ModSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + response.getPsk31ModSettings()->setRfBandwidth(settings.m_rfBandwidth); + response.getPsk31ModSettings()->setGain(settings.m_gain); + response.getPsk31ModSettings()->setChannelMute(settings.m_channelMute ? 1 : 0); + response.getPsk31ModSettings()->setRepeat(settings.m_repeat ? 1 : 0); + response.getPsk31ModSettings()->setRepeatCount(settings.m_repeatCount); + response.getPsk31ModSettings()->setLpfTaps(settings.m_lpfTaps); + response.getPsk31ModSettings()->setRfNoise(settings.m_rfNoise ? 1 : 0); + + if (response.getPsk31ModSettings()->getText()) { + *response.getPsk31ModSettings()->getText() = settings.m_text; + } else { + response.getPsk31ModSettings()->setText(new QString(settings.m_text)); + } + + response.getPsk31ModSettings()->setPulseShaping(settings.m_pulseShaping ? 1 : 0); + response.getPsk31ModSettings()->setBeta(settings.m_beta); + response.getPsk31ModSettings()->setSymbolSpan(settings.m_symbolSpan); + + response.getPsk31ModSettings()->setPrefixCrlf(settings.m_prefixCRLF); + response.getPsk31ModSettings()->setPostfixCrlf(settings.m_postfixCRLF); + + response.getPsk31ModSettings()->setUdpEnabled(settings.m_udpEnabled); + response.getPsk31ModSettings()->setUdpAddress(new QString(settings.m_udpAddress)); + response.getPsk31ModSettings()->setUdpPort(settings.m_udpPort); + + response.getPsk31ModSettings()->setRgbColor(settings.m_rgbColor); + + if (response.getPsk31ModSettings()->getTitle()) { + *response.getPsk31ModSettings()->getTitle() = settings.m_title; + } else { + response.getPsk31ModSettings()->setTitle(new QString(settings.m_title)); + } + + response.getPsk31ModSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); + + if (response.getPsk31ModSettings()->getReverseApiAddress()) { + *response.getPsk31ModSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress; + } else { + response.getPsk31ModSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress)); + } + + response.getPsk31ModSettings()->setReverseApiPort(settings.m_reverseAPIPort); + response.getPsk31ModSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex); + response.getPsk31ModSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex); + + if (settings.m_channelMarker) + { + if (response.getPsk31ModSettings()->getChannelMarker()) + { + settings.m_channelMarker->formatTo(response.getPsk31ModSettings()->getChannelMarker()); + } + else + { + SWGSDRangel::SWGChannelMarker *swgChannelMarker = new SWGSDRangel::SWGChannelMarker(); + settings.m_channelMarker->formatTo(swgChannelMarker); + response.getPsk31ModSettings()->setChannelMarker(swgChannelMarker); + } + } + + if (settings.m_rollupState) + { + if (response.getPsk31ModSettings()->getRollupState()) + { + settings.m_rollupState->formatTo(response.getPsk31ModSettings()->getRollupState()); + } + else + { + SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState(); + settings.m_rollupState->formatTo(swgRollupState); + response.getPsk31ModSettings()->setRollupState(swgRollupState); + } + } +} + +void PSK31::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) +{ + response.getPsk31ModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq())); + response.getPsk31ModReport()->setChannelSampleRate(m_basebandSource->getChannelSampleRate()); +} + +void PSK31::webapiReverseSendSettings(QList& channelSettingsKeys, const PSK31Settings& settings, bool force) +{ + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + + QString channelSettingsURL = QString("http://%1:%2/sdrangel/deviceset/%3/channel/%4/settings") + .arg(settings.m_reverseAPIAddress) + .arg(settings.m_reverseAPIPort) + .arg(settings.m_reverseAPIDeviceIndex) + .arg(settings.m_reverseAPIChannelIndex); + m_networkRequest.setUrl(QUrl(channelSettingsURL)); + m_networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); + + QBuffer *buffer = new QBuffer(); + buffer->open((QBuffer::ReadWrite)); + buffer->write(swgChannelSettings->asJson().toUtf8()); + buffer->seek(0); + + // Always use PATCH to avoid passing reverse API settings + QNetworkReply *reply = m_networkManager->sendCustomRequest(m_networkRequest, "PATCH", buffer); + buffer->setParent(reply); + + delete swgChannelSettings; +} + +void PSK31::sendChannelSettings( + const QList& pipes, + QList& channelSettingsKeys, + const PSK31Settings& settings, + bool force) +{ + for (const auto& pipe : pipes) + { + MessageQueue *messageQueue = qobject_cast(pipe->m_element); + + if (messageQueue) + { + SWGSDRangel::SWGChannelSettings *swgChannelSettings = new SWGSDRangel::SWGChannelSettings(); + webapiFormatChannelSettings(channelSettingsKeys, swgChannelSettings, settings, force); + MainCore::MsgChannelSettings *msg = MainCore::MsgChannelSettings::create( + this, + channelSettingsKeys, + swgChannelSettings, + force + ); + messageQueue->push(msg); + } + } +} + +void PSK31::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const PSK31Settings& settings, + bool force +) +{ + swgChannelSettings->setDirection(1); // single source (Tx) + swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); + swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); + swgChannelSettings->setChannelType(new QString(m_channelId)); + swgChannelSettings->setPsk31ModSettings(new SWGSDRangel::SWGPSK31ModSettings()); + SWGSDRangel::SWGPSK31ModSettings *swgPSK31ModSettings = swgChannelSettings->getPsk31ModSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgPSK31ModSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("rfBandwidth") || force) { + swgPSK31ModSettings->setRfBandwidth(settings.m_rfBandwidth); + } + if (channelSettingsKeys.contains("gain") || force) { + swgPSK31ModSettings->setGain(settings.m_gain); + } + if (channelSettingsKeys.contains("channelMute") || force) { + swgPSK31ModSettings->setChannelMute(settings.m_channelMute ? 1 : 0); + } + if (channelSettingsKeys.contains("repeat") || force) { + swgPSK31ModSettings->setRepeat(settings.m_repeat ? 1 : 0); + } + if (channelSettingsKeys.contains("repeatCount") || force) { + swgPSK31ModSettings->setRepeatCount(settings.m_repeatCount); + } + if (channelSettingsKeys.contains("lpfTaps")) { + swgPSK31ModSettings->setLpfTaps(settings.m_lpfTaps); + } + if (channelSettingsKeys.contains("rfNoise")) { + swgPSK31ModSettings->setRfNoise(settings.m_rfNoise ? 1 : 0); + } + if (channelSettingsKeys.contains("text")) { + swgPSK31ModSettings->setText(new QString(settings.m_text)); + } + if (channelSettingsKeys.contains("beta")) { + swgPSK31ModSettings->setBeta(settings.m_beta); + } + if (channelSettingsKeys.contains("symbolSpan")) { + swgPSK31ModSettings->setSymbolSpan(settings.m_symbolSpan); + } + if (channelSettingsKeys.contains("prefixCRLF")) { + swgPSK31ModSettings->setPrefixCrlf(settings.m_prefixCRLF); + } + if (channelSettingsKeys.contains("postfixCRLF")) { + swgPSK31ModSettings->setPostfixCrlf(settings.m_postfixCRLF); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgPSK31ModSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("title") || force) { + swgPSK31ModSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgPSK31ModSettings->setStreamIndex(settings.m_streamIndex); + } + if (channelSettingsKeys.contains("udpEnabled") || force) { + swgPSK31ModSettings->setUdpEnabled(settings.m_udpEnabled); + } + if (channelSettingsKeys.contains("udpAddress") || force) { + swgPSK31ModSettings->setUdpAddress(new QString(settings.m_udpAddress)); + } + if (channelSettingsKeys.contains("udpPort") || force) { + swgPSK31ModSettings->setUdpPort(settings.m_udpPort); + } + + if (settings.m_channelMarker && (channelSettingsKeys.contains("channelMarker") || force)) + { + SWGSDRangel::SWGChannelMarker *swgChannelMarker = new SWGSDRangel::SWGChannelMarker(); + settings.m_channelMarker->formatTo(swgChannelMarker); + swgPSK31ModSettings->setChannelMarker(swgChannelMarker); + } + + if (settings.m_rollupState && (channelSettingsKeys.contains("rollupState") || force)) + { + SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState(); + settings.m_rollupState->formatTo(swgRollupState); + swgPSK31ModSettings->setRollupState(swgRollupState); + } +} + +void PSK31::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "PSK31::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + } + else + { + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("PSK31::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); + } + + reply->deleteLater(); +} + +double PSK31::getMagSq() const +{ + return m_basebandSource->getMagSq(); +} + +void PSK31::setLevelMeter(QObject *levelMeter) +{ + connect(m_basebandSource, SIGNAL(levelChanged(qreal, qreal, int)), levelMeter, SLOT(levelChanged(qreal, qreal, int))); +} + +uint32_t PSK31::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSinkStreams(); +} + +int PSK31::getSourceChannelSampleRate() const +{ + return m_basebandSource->getSourceChannelSampleRate(); +} + +void PSK31::openUDP(const PSK31Settings& settings) +{ + closeUDP(); + m_udpSocket = new QUdpSocket(); + if (!m_udpSocket->bind(QHostAddress(settings.m_udpAddress), settings.m_udpPort)) + qCritical() << "PSK31::openUDP: Failed to bind to port " << settings.m_udpAddress << ":" << settings.m_udpPort << ". Error: " << m_udpSocket->error(); + else + qDebug() << "PSK31::openUDP: Listening for text on " << settings.m_udpAddress << ":" << settings.m_udpPort; + connect(m_udpSocket, &QUdpSocket::readyRead, this, &PSK31::udpRx); +} + +void PSK31::closeUDP() +{ + if (m_udpSocket != nullptr) + { + disconnect(m_udpSocket, &QUdpSocket::readyRead, this, &PSK31::udpRx); + delete m_udpSocket; + m_udpSocket = nullptr; + } +} + +void PSK31::udpRx() +{ + while (m_udpSocket->hasPendingDatagrams()) + { + QNetworkDatagram datagram = m_udpSocket->receiveDatagram(); + MsgTXText *msg = MsgTXText::create(QString(datagram.data())); + m_basebandSource->getInputMessageQueue()->push(msg); + } +} + +void PSK31::setMessageQueueToGUI(MessageQueue* queue) { + ChannelAPI::setMessageQueueToGUI(queue); + m_basebandSource->setMessageQueueToGUI(queue); +} diff --git a/plugins/channeltx/modpsk31/psk31mod.h b/plugins/channeltx/modpsk31/psk31mod.h new file mode 100644 index 0000000000..9fb4e1cee0 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31mod.h @@ -0,0 +1,246 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016-2019 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 PLUGINS_CHANNELTX_MODPSK31_PSK31MOD_H_ +#define PLUGINS_CHANNELTX_MODPSK31_PSK31MOD_H_ + +#include +#include +#include + +#include +#include + +#include "dsp/basebandsamplesource.h" +#include "dsp/spectrumvis.h" +#include "channel/channelapi.h" +#include "util/message.h" + +#include "psk31modsettings.h" + +class QNetworkAccessManager; +class QNetworkReply; +class QThread; +class QUdpSocket; +class DeviceAPI; +class PSK31Baseband; +class ObjectPipe; + +class PSK31 : public BasebandSampleSource, public ChannelAPI { +public: + class MsgConfigurePSK31 : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PSK31Settings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigurePSK31* create(const PSK31Settings& settings, bool force) + { + return new MsgConfigurePSK31(settings, force); + } + + private: + PSK31Settings m_settings; + bool m_force; + + MsgConfigurePSK31(const PSK31Settings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + class MsgTx : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgTx* create() { + return new MsgTx(); + } + + private: + MsgTx() : + Message() + { } + }; + + class MsgReportTx : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const QString& getText() const { return m_text; } + int getBufferedCharacters() const { return m_bufferedCharacters; } + + static MsgReportTx* create(const QString& text, int bufferedCharacters) { + return new MsgReportTx(text, bufferedCharacters); + } + + private: + QString m_text; + int m_bufferedCharacters; + + MsgReportTx(const QString& text, int bufferedCharacters) : + Message(), + m_text(text), + m_bufferedCharacters(bufferedCharacters) + { } + }; + + class MsgTXText : public Message { + MESSAGE_CLASS_DECLARATION + + public: + static MsgTXText* create(QString text) + { + return new MsgTXText(text); + } + + QString m_text; + + private: + + MsgTXText(QString text) : + Message(), + m_text(text) + { } + }; + + //================================================================= + + PSK31(DeviceAPI *deviceAPI); + virtual ~PSK31(); + virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } + + virtual void start(); + virtual void stop(); + virtual void pull(SampleVector::iterator& begin, unsigned int nbSamples); + virtual void pushMessage(Message *msg) { m_inputMessageQueue.push(msg); } + virtual QString getSourceName() { return objectName(); } + + virtual void getIdentifier(QString& id) { id = objectName(); } + virtual QString getIdentifier() const { return objectName(); } + virtual void getTitle(QString& title) { title = m_settings.m_title; } + virtual qint64 getCenterFrequency() const { return m_settings.m_inputFrequencyOffset; } + virtual void setCenterFrequency(qint64 frequency); + + virtual QByteArray serialize() const; + virtual bool deserialize(const QByteArray& data); + + virtual int getNbSinkStreams() const { return 1; } + virtual int getNbSourceStreams() const { return 0; } + + virtual qint64 getStreamCenterFrequency(int streamIndex, bool sinkElseSource) const + { + (void) streamIndex; + (void) sinkElseSource; + return m_settings.m_inputFrequencyOffset; + } + + virtual int webapiSettingsGet( + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage); + + virtual int webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage); + + virtual int webapiReportGet( + SWGSDRangel::SWGChannelReport& response, + QString& errorMessage); + + virtual int webapiActionsPost( + const QStringList& channelActionsKeys, + SWGSDRangel::SWGChannelActions& query, + QString& errorMessage); + + static void webapiFormatChannelSettings( + SWGSDRangel::SWGChannelSettings& response, + const PSK31Settings& settings); + + static void webapiUpdateChannelSettings( + PSK31Settings& settings, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response); + + SpectrumVis *getSpectrumVis() { return &m_spectrumVis; } + double getMagSq() const; + void setLevelMeter(QObject *levelMeter); + uint32_t getNumberOfDeviceStreams() const; + int getSourceChannelSampleRate() const; + void setMessageQueueToGUI(MessageQueue* queue) override; + + static const char* const m_channelIdURI; + static const char* const m_channelId; + +private: + enum RateState { + RSInitialFill, + RSRunning + }; + + DeviceAPI* m_deviceAPI; + QThread *m_thread; + PSK31Baseband* m_basebandSource; + PSK31Settings m_settings; + SpectrumVis m_spectrumVis; + + SampleVector m_sampleBuffer; + QRecursiveMutex m_settingsMutex; + + int m_sampleRate; + + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + QUdpSocket *m_udpSocket; + + virtual bool handleMessage(const Message& cmd); + void applySettings(const PSK31Settings& settings, bool force = false); + void sendSampleRateToDemodAnalyzer(); + void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); + void webapiReverseSendSettings(QList& channelSettingsKeys, const PSK31Settings& settings, bool force); + void sendChannelSettings( + const QList& pipes, + QList& channelSettingsKeys, + const PSK31Settings& settings, + bool force + ); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const PSK31Settings& settings, + bool force + ); + void openUDP(const PSK31Settings& settings); + void closeUDP(); + +private slots: + void networkManagerFinished(QNetworkReply *reply); + void udpRx(); +}; + + +#endif /* PLUGINS_CHANNELTX_MODPSK31_PSK31MOD_H_ */ diff --git a/plugins/channeltx/modpsk31/psk31modbaseband.cpp b/plugins/channeltx/modpsk31/psk31modbaseband.cpp new file mode 100644 index 0000000000..1d99eb8c93 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modbaseband.cpp @@ -0,0 +1,200 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 "dsp/upchannelizer.h" +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" + +#include "psk31modbaseband.h" +#include "psk31mod.h" + +MESSAGE_CLASS_DEFINITION(PSK31Baseband::MsgConfigurePSK31Baseband, Message) + +PSK31Baseband::PSK31Baseband() +{ + m_sampleFifo.resize(SampleSourceFifo::getSizePolicy(48000)); + m_channelizer = new UpChannelizer(&m_source); + + qDebug("PSK31Baseband::PSK31Baseband"); + QObject::connect( + &m_sampleFifo, + &SampleSourceFifo::dataRead, + this, + &PSK31Baseband::handleData, + Qt::QueuedConnection + ); + + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); +} + +PSK31Baseband::~PSK31Baseband() +{ + delete m_channelizer; +} + +void PSK31Baseband::reset() +{ + QMutexLocker mutexLocker(&m_mutex); + m_sampleFifo.reset(); +} + +void PSK31Baseband::setChannel(ChannelAPI *channel) +{ + m_source.setChannel(channel); +} + +void PSK31Baseband::pull(const SampleVector::iterator& begin, unsigned int nbSamples) +{ + unsigned int part1Begin, part1End, part2Begin, part2End; + m_sampleFifo.read(nbSamples, part1Begin, part1End, part2Begin, part2End); + SampleVector& data = m_sampleFifo.getData(); + + if (part1Begin != part1End) + { + std::copy( + data.begin() + part1Begin, + data.begin() + part1End, + begin + ); + } + + unsigned int shift = part1End - part1Begin; + + if (part2Begin != part2End) + { + std::copy( + data.begin() + part2Begin, + data.begin() + part2End, + begin + shift + ); + } +} + +void PSK31Baseband::handleData() +{ + QMutexLocker mutexLocker(&m_mutex); + SampleVector& data = m_sampleFifo.getData(); + unsigned int ipart1begin; + unsigned int ipart1end; + unsigned int ipart2begin; + unsigned int ipart2end; + qreal rmsLevel, peakLevel; + int numSamples; + + unsigned int remainder = m_sampleFifo.remainder(); + + while ((remainder > 0) && (m_inputMessageQueue.size() == 0)) + { + m_sampleFifo.write(remainder, ipart1begin, ipart1end, ipart2begin, ipart2end); + + if (ipart1begin != ipart1end) { // first part of FIFO data + processFifo(data, ipart1begin, ipart1end); + } + + if (ipart2begin != ipart2end) { // second part of FIFO data (used when block wraps around) + processFifo(data, ipart2begin, ipart2end); + } + + remainder = m_sampleFifo.remainder(); + } + + m_source.getLevels(rmsLevel, peakLevel, numSamples); + emit levelChanged(rmsLevel, peakLevel, numSamples); +} + +void PSK31Baseband::processFifo(SampleVector& data, unsigned int iBegin, unsigned int iEnd) +{ + m_channelizer->prefetch(iEnd - iBegin); + m_channelizer->pull(data.begin() + iBegin, iEnd - iBegin); +} + +void PSK31Baseband::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +bool PSK31Baseband::handleMessage(const Message& cmd) +{ + if (MsgConfigurePSK31Baseband::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + MsgConfigurePSK31Baseband& cfg = (MsgConfigurePSK31Baseband&) cmd; + qDebug() << "PSK31Baseband::handleMessage: MsgConfigurePSK31Baseband"; + + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (PSK31::MsgTx::match(cmd)) + { + qDebug() << "PSK31Baseband::handleMessage: MsgTx"; + m_source.addTXText(m_settings.m_text); + + return true; + } + else if (PSK31::MsgTXText::match(cmd)) + { + PSK31::MsgTXText& tx = (PSK31::MsgTXText&) cmd; + m_source.addTXText(tx.m_text); + + return true; + } + else if (DSPSignalNotification::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + DSPSignalNotification& notif = (DSPSignalNotification&) cmd; + qDebug() << "PSK31Baseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate(); + m_sampleFifo.resize(SampleSourceFifo::getSizePolicy(notif.getSampleRate())); + m_channelizer->setBasebandSampleRate(notif.getSampleRate()); + m_source.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); + + return true; + } + else + { + qDebug() << "PSK31Baseband - Baseband got unknown message"; + return false; + } +} + +void PSK31Baseband::applySettings(const PSK31Settings& settings, bool force) +{ + if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) + { + m_channelizer->setChannelization(m_channelizer->getChannelSampleRate(), settings.m_inputFrequencyOffset); + m_source.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); + } + + m_source.applySettings(settings, force); + + m_settings = settings; +} + +int PSK31Baseband::getChannelSampleRate() const +{ + return m_channelizer->getChannelSampleRate(); +} diff --git a/plugins/channeltx/modpsk31/psk31modbaseband.h b/plugins/channeltx/modpsk31/psk31modbaseband.h new file mode 100644 index 0000000000..d56d23b34b --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modbaseband.h @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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_PSK31MODBASEBAND_H +#define INCLUDE_PSK31MODBASEBAND_H + +#include +#include + +#include "dsp/samplesourcefifo.h" +#include "util/message.h" +#include "util/messagequeue.h" + +#include "psk31modsource.h" + +class UpChannelizer; +class ChannelAPI; + +class PSK31Baseband : public QObject +{ + Q_OBJECT +public: + class MsgConfigurePSK31Baseband : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const PSK31Settings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigurePSK31Baseband* create(const PSK31Settings& settings, bool force) + { + return new MsgConfigurePSK31Baseband(settings, force); + } + + private: + PSK31Settings m_settings; + bool m_force; + + MsgConfigurePSK31Baseband(const PSK31Settings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + PSK31Baseband(); + ~PSK31Baseband(); + void reset(); + void pull(const SampleVector::iterator& begin, unsigned int nbSamples); + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication + void setMessageQueueToGUI(MessageQueue* messageQueue) { m_source.setMessageQueueToGUI(messageQueue); } + double getMagSq() const { return m_source.getMagSq(); } + int getChannelSampleRate() const; + void setSpectrumSampleSink(BasebandSampleSink* sampleSink) { m_source.setSpectrumSink(sampleSink); } + void setChannel(ChannelAPI *channel); + int getSourceChannelSampleRate() const { return m_source.getChannelSampleRate(); } + +signals: + /** + * Level changed + * \param rmsLevel RMS level in range 0.0 - 1.0 + * \param peakLevel Peak level in range 0.0 - 1.0 + * \param numSamples Number of audio samples analyzed + */ + void levelChanged(qreal rmsLevel, qreal peakLevel, int numSamples); + +private: + SampleSourceFifo m_sampleFifo; + UpChannelizer *m_channelizer; + PSK31Source m_source; + MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication + PSK31Settings m_settings; + QRecursiveMutex m_mutex; + + void processFifo(SampleVector& data, unsigned int iBegin, unsigned int iEnd); + bool handleMessage(const Message& cmd); + void applySettings(const PSK31Settings& settings, bool force = false); + +private slots: + void handleInputMessages(); + void handleData(); //!< Handle data when samples have to be processed +}; + + +#endif // INCLUDE_PSK31MODBASEBAND_H diff --git a/plugins/channeltx/modpsk31/psk31modgui.cpp b/plugins/channeltx/modpsk31/psk31modgui.cpp new file mode 100644 index 0000000000..8cb285c2ed --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modgui.cpp @@ -0,0 +1,538 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 "dsp/spectrumvis.h" +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "device/deviceuiset.h" +#include "plugin/pluginapi.h" +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "util/db.h" +#include "util/rtty.h" +#include "util/maidenhead.h" +#include "gui/glspectrum.h" +#include "gui/crightclickenabler.h" +#include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" +#include "gui/fmpreemphasisdialog.h" +#include "gui/dialpopup.h" +#include "gui/dialogpositioner.h" +#include "maincore.h" + +#include "ui_psk31modgui.h" +#include "psk31modgui.h" +#include "psk31modrepeatdialog.h" +#include "psk31modtxsettingsdialog.h" + +PSK31GUI* PSK31GUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx) +{ + PSK31GUI* gui = new PSK31GUI(pluginAPI, deviceUISet, channelTx); + return gui; +} + +void PSK31GUI::destroy() +{ + delete this; +} + +void PSK31GUI::resetToDefaults() +{ + m_settings.resetToDefaults(); + displaySettings(); + applySettings(true); +} + +QByteArray PSK31GUI::serialize() const +{ + return m_settings.serialize(); +} + +bool PSK31GUI::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) { + displaySettings(); + applySettings(true); + return true; + } else { + resetToDefaults(); + return false; + } +} + +bool PSK31GUI::handleMessage(const Message& message) +{ + if (PSK31::MsgConfigurePSK31::match(message)) + { + const PSK31::MsgConfigurePSK31& cfg = (PSK31::MsgConfigurePSK31&) message; + m_settings = cfg.getSettings(); + blockApplySettings(true); + m_channelMarker.updateSettings(static_cast(m_settings.m_channelMarker)); + displaySettings(); + blockApplySettings(false); + return true; + } + else if (PSK31::MsgReportTx::match(message)) + { + const PSK31::MsgReportTx& report = (PSK31::MsgReportTx&)message; + QString s = report.getText(); + int bufferedCharacters = report.getBufferedCharacters(); + + // Turn TX button green when transmitting + QString tooltip = m_initialToolTip; + if (bufferedCharacters == 0) + { + ui->txButton->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + } + else + { + ui->txButton->setStyleSheet("QToolButton { background-color : green; }"); + tooltip.append(QString("\n\n%1 characters in buffer").arg(bufferedCharacters)); + } + ui->txButton->setToolTip(tooltip); + + s = s.replace("\r", ""); // Don't display carriage returns + + if (!s.isEmpty()) + { + // Is the scroll bar at the bottom? + int scrollPos = ui->transmittedText->verticalScrollBar()->value(); + bool atBottom = scrollPos >= ui->transmittedText->verticalScrollBar()->maximum(); + + // Move cursor to end where we want to append new text + // (user may have moved it by clicking / highlighting text) + ui->transmittedText->moveCursor(QTextCursor::End); + + // Restore scroll position + ui->transmittedText->verticalScrollBar()->setValue(scrollPos); + + // Insert text + ui->transmittedText->insertPlainText(s); + + // Scroll to bottom, if we we're previously at the bottom + if (atBottom) { + ui->transmittedText->verticalScrollBar()->setValue(ui->transmittedText->verticalScrollBar()->maximum()); + } + } + return true; + } + else if (DSPSignalNotification::match(message)) + { + const DSPSignalNotification& notif = (const DSPSignalNotification&) message; + m_deviceCenterFrequency = notif.getCenterFrequency(); + m_basebandSampleRate = notif.getSampleRate(); + ui->deltaFrequency->setValueRange(false, 7, -m_basebandSampleRate/2, m_basebandSampleRate/2); + ui->deltaFrequencyLabel->setToolTip(tr("Range %1 %L2 Hz").arg(QChar(0xB1)).arg(m_basebandSampleRate/2)); + updateAbsoluteCenterFrequency(); + return true; + } + else + { + return false; + } +} + +void PSK31GUI::channelMarkerChangedByCursor() +{ + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + applySettings(); +} + +void PSK31GUI::handleSourceMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + if (handleMessage(*message)) + { + delete message; + } + } +} + +void PSK31GUI::on_deltaFrequency_changed(qint64 value) +{ + m_channelMarker.setCenterFrequency(value); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); + applySettings(); +} + +void PSK31GUI::on_rfBW_valueChanged(int value) +{ + int bw = value; + ui->rfBWText->setText(QString("%1 Hz").arg(bw)); + m_channelMarker.setBandwidth(bw); + m_settings.m_rfBandwidth = bw; + applySettings(); +} + +void PSK31GUI::on_clearTransmittedText_clicked() +{ + ui->transmittedText->clear(); +} + +void PSK31GUI::on_gain_valueChanged(int value) +{ + ui->gainText->setText(QString("%1dB").arg(value)); + m_settings.m_gain = value; + applySettings(); +} + +void PSK31GUI::on_channelMute_toggled(bool checked) +{ + m_settings.m_channelMute = checked; + applySettings(); +} + +void PSK31GUI::on_txButton_clicked() +{ + transmit(ui->text->currentText()); +} + +void PSK31GUI::on_text_returnPressed() +{ + transmit(ui->text->currentText()); + ui->text->setCurrentText(""); +} + +void PSK31GUI::on_text_editingFinished() +{ + m_settings.m_text = ui->text->currentText(); + applySettings(); +} + +void PSK31GUI::on_repeat_toggled(bool checked) +{ + m_settings.m_repeat = checked; + applySettings(); +} + +void PSK31GUI::repeatSelect(const QPoint& p) +{ + PSK31RepeatDialog dialog(m_settings.m_repeatCount); + dialog.move(p); + new DialogPositioner(&dialog, false); + + if (dialog.exec() == QDialog::Accepted) + { + m_settings.m_repeatCount = dialog.m_repeatCount; + applySettings(); + } +} + +void PSK31GUI::txSettingsSelect(const QPoint& p) +{ + PSK31TXSettingsDialog dialog(&m_settings); + dialog.move(p); + new DialogPositioner(&dialog, false); + + if (dialog.exec() == QDialog::Accepted) + { + displaySettings(); + applySettings(); + } +} + +void PSK31GUI::on_udpEnabled_clicked(bool checked) +{ + m_settings.m_udpEnabled = checked; + applySettings(); +} + +void PSK31GUI::on_udpAddress_editingFinished() +{ + m_settings.m_udpAddress = ui->udpAddress->text(); + applySettings(); +} + +void PSK31GUI::on_udpPort_editingFinished() +{ + m_settings.m_udpPort = ui->udpPort->text().toInt(); + applySettings(); +} + +void PSK31GUI::onWidgetRolled(QWidget* widget, bool rollDown) +{ + (void) widget; + (void) rollDown; + + getRollupContents()->saveState(m_rollupState); + applySettings(); +} + +void PSK31GUI::onMenuDialogCalled(const QPoint &p) +{ + if (m_contextMenuType == ContextMenuChannelSettings) + { + BasicChannelSettingsDialog dialog(&m_channelMarker, 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.setReverseAPIChannelIndex(m_settings.m_reverseAPIChannelIndex); + dialog.setDefaultTitle(m_displayedName); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + dialog.setNumberOfStreams(m_psk31Mod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + + dialog.move(p); + new DialogPositioner(&dialog, false); + dialog.exec(); + + m_settings.m_rgbColor = m_channelMarker.getColor().rgb(); + m_settings.m_title = m_channelMarker.getTitle(); + m_settings.m_useReverseAPI = dialog.useReverseAPI(); + m_settings.m_reverseAPIAddress = dialog.getReverseAPIAddress(); + m_settings.m_reverseAPIPort = dialog.getReverseAPIPort(); + m_settings.m_reverseAPIDeviceIndex = dialog.getReverseAPIDeviceIndex(); + m_settings.m_reverseAPIChannelIndex = dialog.getReverseAPIChannelIndex(); + + setWindowTitle(m_settings.m_title); + setTitle(m_channelMarker.getTitle()); + setTitleColor(m_settings.m_rgbColor); + + if (m_deviceUISet->m_deviceMIMOEngine) + { + m_settings.m_streamIndex = dialog.getSelectedStreamIndex(); + m_channelMarker.clearStreamIndexes(); + m_channelMarker.addStreamIndex(m_settings.m_streamIndex); + updateIndexLabel(); + } + + applySettings(); + } + + resetContextMenuType(); +} + +PSK31GUI::PSK31GUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget* parent) : + ChannelGUI(parent), + ui(new Ui::PSK31GUI), + m_pluginAPI(pluginAPI), + m_deviceUISet(deviceUISet), + m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), + m_doApplySettings(true) +{ + setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/channeltx/modpsk31/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + + m_psk31Mod = (PSK31*) channelTx; + m_psk31Mod->setMessageQueueToGUI(getInputMessageQueue()); + + connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + + m_spectrumVis = m_psk31Mod->getSpectrumVis(); + m_spectrumVis->setGLSpectrum(ui->glSpectrum); + + ui->spectrumGUI->setBuddies(m_spectrumVis, ui->glSpectrum); + + ui->glSpectrum->setCenterFrequency(0); + ui->glSpectrum->setSampleRate(2000); + ui->glSpectrum->setLsbDisplay(false); + + SpectrumSettings spectrumSettings = m_spectrumVis->getSettings(); + spectrumSettings.m_ssb = false; + spectrumSettings.m_displayCurrent = true; + spectrumSettings.m_displayWaterfall = false; + spectrumSettings.m_displayMaxHold = false; + spectrumSettings.m_displayHistogram = false; + SpectrumVis::MsgConfigureSpectrumVis *msg = SpectrumVis::MsgConfigureSpectrumVis::create(spectrumSettings, false); + m_spectrumVis->getInputMessageQueue()->push(msg); + + CRightClickEnabler *repeatRightClickEnabler = new CRightClickEnabler(ui->repeat); + connect(repeatRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(repeatSelect(const QPoint &))); + + CRightClickEnabler *txRightClickEnabler = new CRightClickEnabler(ui->txButton); + connect(txRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(txSettingsSelect(const QPoint &))); + + ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); + ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); + + m_channelMarker.blockSignals(true); + m_channelMarker.setColor(Qt::red); + m_channelMarker.setBandwidth(12500); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setTitle("PSK31 Modulator"); + m_channelMarker.setSourceOrSinkStream(false); + m_channelMarker.blockSignals(false); + m_channelMarker.setVisible(true); // activate signal on the last setting only + + m_deviceUISet->addChannelMarker(&m_channelMarker); + + connect(&m_channelMarker, SIGNAL(changedByCursor()), this, SLOT(channelMarkerChangedByCursor())); + + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); + m_psk31Mod->setLevelMeter(ui->volumeMeter); + + m_settings.setChannelMarker(&m_channelMarker); + m_settings.setRollupState(&m_rollupState); + + ui->transmittedText->addAcronyms(Rtty::m_acronyms); + + ui->spectrumContainer->setVisible(false); + + displaySettings(); + makeUIConnections(); + applySettings(); + DialPopup::addPopupsToChildDials(this); + + m_initialToolTip = ui->txButton->toolTip(); +} + +PSK31GUI::~PSK31GUI() +{ + // If we don't disconnect, we can get this signal after this has been deleted! + QObject::disconnect(ui->text->lineEdit(), &QLineEdit::editingFinished, this, &PSK31GUI::on_text_editingFinished); + delete ui; +} + +void PSK31GUI::transmit(const QString& text) +{ + PSK31::MsgTXText*msg = PSK31::MsgTXText::create(text); + m_psk31Mod->getInputMessageQueue()->push(msg); +} + +void PSK31GUI::blockApplySettings(bool block) +{ + m_doApplySettings = !block; +} + +void PSK31GUI::applySettings(bool force) +{ + if (m_doApplySettings) + { + PSK31::MsgConfigurePSK31 *msg = PSK31::MsgConfigurePSK31::create(m_settings, force); + m_psk31Mod->getInputMessageQueue()->push(msg); + } +} + +QString PSK31GUI::substitute(const QString& text) +{ + const MainSettings& mainSettings = MainCore::instance()->getSettings(); + QString location = Maidenhead::toMaidenhead(mainSettings.getLatitude(), mainSettings.getLongitude()); + QString s = text; + + s = s.replace("${callsign}", mainSettings.getStationName().toUpper()); + s = s.replace("${location}", location); + + return s; +} + +void PSK31GUI::displaySettings() +{ + m_channelMarker.blockSignals(true); + m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); + m_channelMarker.setTitle(m_settings.m_title); + m_channelMarker.setBandwidth(m_settings.m_rfBandwidth); + m_channelMarker.blockSignals(false); + m_channelMarker.setColor(m_settings.m_rgbColor); // activate signal on the last setting only + + setTitleColor(m_settings.m_rgbColor); + setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); + updateIndexLabel(); + + blockApplySettings(true); + + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + + ui->rfBWText->setText(QString("%1 Hz").arg(m_settings.m_rfBandwidth)); + ui->rfBW->setValue(m_settings.m_rfBandwidth); + + ui->udpEnabled->setChecked(m_settings.m_udpEnabled); + ui->udpAddress->setText(m_settings.m_udpAddress); + ui->udpPort->setText(QString::number(m_settings.m_udpPort)); + + ui->gainText->setText(QString("%1dB").arg((double)m_settings.m_gain, 0, 'f', 1)); + ui->gain->setValue(m_settings.m_gain); + + ui->channelMute->setChecked(m_settings.m_channelMute); + ui->repeat->setChecked(m_settings.m_repeat); + + ui->text->clear(); + for (const auto& text : m_settings.m_predefinedTexts) { + ui->text->addItem(substitute(text)); + } + ui->text->setCurrentText(m_settings.m_text); + + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); + blockApplySettings(false); +} + +void PSK31GUI::leaveEvent(QEvent* event) +{ + m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); +} + +void PSK31GUI::enterEvent(EnterEventType* event) +{ + m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); +} + +void PSK31GUI::tick() +{ + double powDb = CalcDb::dbPower(m_psk31Mod->getMagSq()); + m_channelPowerDbAvg(powDb); + ui->channelPower->setText(tr("%1 dB").arg(m_channelPowerDbAvg.asDouble(), 0, 'f', 1)); +} + +void PSK31GUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &PSK31GUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &PSK31GUI::on_rfBW_valueChanged); + QObject::connect(ui->clearTransmittedText, &QToolButton::clicked, this, &PSK31GUI::on_clearTransmittedText_clicked); + QObject::connect(ui->gain, &QDial::valueChanged, this, &PSK31GUI::on_gain_valueChanged); + QObject::connect(ui->channelMute, &QToolButton::toggled, this, &PSK31GUI::on_channelMute_toggled); + QObject::connect(ui->txButton, &QToolButton::clicked, this, &PSK31GUI::on_txButton_clicked); + QObject::connect(ui->text->lineEdit(), &QLineEdit::editingFinished, this, &PSK31GUI::on_text_editingFinished); + QObject::connect(ui->text->lineEdit(), &QLineEdit::returnPressed, this, &PSK31GUI::on_text_returnPressed); + QObject::connect(ui->repeat, &ButtonSwitch::toggled, this, &PSK31GUI::on_repeat_toggled); + QObject::connect(ui->udpEnabled, &QCheckBox::clicked, this, &PSK31GUI::on_udpEnabled_clicked); + QObject::connect(ui->udpAddress, &QLineEdit::editingFinished, this, &PSK31GUI::on_udpAddress_editingFinished); + QObject::connect(ui->udpPort, &QLineEdit::editingFinished, this, &PSK31GUI::on_udpPort_editingFinished); +} + +void PSK31GUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channeltx/modpsk31/psk31modgui.h b/plugins/channeltx/modpsk31/psk31modgui.h new file mode 100644 index 0000000000..3e6be55b68 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modgui.h @@ -0,0 +1,123 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 PLUGINS_CHANNELTX_MODPSK31_PSK31MODGUI_H_ +#define PLUGINS_CHANNELTX_MODPSK31_PSK31MODGUI_H_ + +#include "channel/channelgui.h" +#include "dsp/channelmarker.h" +#include "util/movingaverage.h" +#include "util/messagequeue.h" +#include "settings/rollupstate.h" + +#include "psk31mod.h" +#include "psk31modsettings.h" + +class PluginAPI; +class DeviceUISet; +class BasebandSampleSource; +class SpectrumVis; + +namespace Ui { + class PSK31GUI; +} + +class PSK31GUI : public ChannelGUI { + Q_OBJECT + +public: + static PSK31GUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx); + virtual void destroy(); + + void resetToDefaults(); + QByteArray serialize() const; + bool deserialize(const QByteArray& data); + virtual MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } + virtual void setWorkspaceIndex(int index) { m_settings.m_workspaceIndex = index; }; + virtual int getWorkspaceIndex() const { return m_settings.m_workspaceIndex; }; + virtual void setGeometryBytes(const QByteArray& blob) { m_settings.m_geometryBytes = blob; }; + virtual QByteArray getGeometryBytes() const { return m_settings.m_geometryBytes; }; + virtual QString getTitle() const { return m_settings.m_title; }; + virtual QColor getTitleColor() const { return m_settings.m_rgbColor; }; + virtual void zetHidden(bool hidden) { m_settings.m_hidden = hidden; } + virtual bool getHidden() const { return m_settings.m_hidden; } + virtual ChannelMarker& getChannelMarker() { return m_channelMarker; } + virtual int getStreamIndex() const { return m_settings.m_streamIndex; } + virtual void setStreamIndex(int streamIndex) { m_settings.m_streamIndex = streamIndex; } + +public slots: + void channelMarkerChangedByCursor(); + +private: + Ui::PSK31GUI* ui; + PluginAPI* m_pluginAPI; + DeviceUISet* m_deviceUISet; + ChannelMarker m_channelMarker; + RollupState m_rollupState; + PSK31Settings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; + bool m_doApplySettings; + SpectrumVis* m_spectrumVis; + QString m_initialToolTip; + + PSK31* m_psk31Mod; + MovingAverageUtil m_channelPowerDbAvg; + + MessageQueue m_inputMessageQueue; + + explicit PSK31GUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSource *channelTx, QWidget* parent = 0); + virtual ~PSK31GUI(); + + void transmit(const QString& str); + void blockApplySettings(bool block); + void applySettings(bool force = false); + void displaySettings(); + bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + QString substitute(const QString& text); + + void leaveEvent(QEvent*); + void enterEvent(EnterEventType*); + +private slots: + void handleSourceMessages(); + + void on_deltaFrequency_changed(qint64 value); + void on_rfBW_valueChanged(int index); + void on_gain_valueChanged(int value); + void on_channelMute_toggled(bool checked); + void on_clearTransmittedText_clicked(); + void on_txButton_clicked(); + void on_text_editingFinished(); + void on_text_returnPressed(); + void on_repeat_toggled(bool checked); + void repeatSelect(const QPoint& p); + void txSettingsSelect(const QPoint& p); + void on_udpEnabled_clicked(bool checked); + void on_udpAddress_editingFinished(); + void on_udpPort_editingFinished(); + + void onWidgetRolled(QWidget* widget, bool rollDown); + void onMenuDialogCalled(const QPoint& p); + + void tick(); +}; + +#endif /* PLUGINS_CHANNELTX_MODPSK31_PSK31MODGUI_H_ */ diff --git a/plugins/channeltx/modpsk31/psk31modgui.ui b/plugins/channeltx/modpsk31/psk31modgui.ui new file mode 100644 index 0000000000..e02bae2502 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modgui.ui @@ -0,0 +1,650 @@ + + + PSK31GUI + + + + 0 + 0 + 396 + 700 + + + + + 0 + 0 + + + + + 390 + 0 + + + + + Liberation Sans + 9 + + + + Qt::StrongFocus + + + PSK31 Modulator + + + + true + + + + 2 + 2 + 391 + 161 + + + + + 280 + 0 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + 2 + + + + + + + + 16 + 0 + + + + Df + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Demod shift frequency from center in Hz + + + + + + + Hz + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 0 + + + + Channel power + + + Qt::RightToLeft + + + -100.0 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Mute/Unmute channel + + + ... + + + + :/txon.png + :/txoff.png:/txon.png + + + true + + + + + + + + + + + BW + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + RF bandwidth + + + 10 + + + 500 + + + 1 + + + 10 + + + 100 + + + Qt::Horizontal + + + + + + + + 30 + 0 + + + + 500 Hz + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + Qt::Horizontal + + + + + + + + + + 24 + 24 + + + + Gain + + + -60 + + + 0 + + + 5 + + + 1 + + + 0 + + + + + + + Gain + + + + + + + + 30 + 0 + + + + Audio input gain value + + + -80.0dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + Liberation Mono + 8 + + + + Level (% full range) top trace: average, bottom trace: instantaneous peak, tip: peak hold + + + + + + + + + Qt::Horizontal + + + + + + + + + Forward text received via UDP + + + Qt::RightToLeft + + + UDP + + + + + + + + 120 + 0 + + + + Qt::ClickFocus + + + UDP address to listen for text to forward on + + + 000.000.000.000 + + + 127.0.0.1 + + + + + + + : + + + Qt::AlignCenter + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + + + + Qt::ClickFocus + + + UDP port to listen for text to forward on + + + 00000 + + + 9997 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Repeatedly transmit the text. Right click for additional settings. + + + ... + + + + :/playloop.png:/playloop.png + + + + + + + Clear transmitted text + + + + + + + :/bin.png:/bin.png + + + + + + + + + Qt::Horizontal + + + + + + + + + Text to send + + + true + + + + + + + Press to transmit the text. Right click for additional settings. + + + TX + + + + + + + + + + + 0 + 220 + 391 + 141 + + + + + 0 + 0 + + + + Transmitted Text + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + + + + + 0 + 370 + 381 + 284 + + + + + 0 + 0 + + + + Baseband Spectrum + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + 200 + 250 + + + + + Liberation Mono + 8 + + + + + + + + + + + + + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
+ + GLSpectrum + QWidget +
gui/glspectrum.h
+ 1 +
+ + GLSpectrumGUI + QWidget +
gui/glspectrumgui.h
+ 1 +
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + LevelMeterVU + QWidget +
gui/levelmeter.h
+ 1 +
+ + AcronymView + QTextEdit +
gui/acronymview.h
+ 1 +
+
+ + deltaFrequency + channelMute + rfBW + txButton + transmittedText + + + + + +
diff --git a/plugins/channeltx/modpsk31/psk31modplugin.cpp b/plugins/channeltx/modpsk31/psk31modplugin.cpp new file mode 100644 index 0000000000..e500b04d62 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modplugin.cpp @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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" + +#ifndef SERVER_MODE +#include "psk31modgui.h" +#endif +#include "psk31mod.h" +#include "psk31modwebapiadapter.h" +#include "psk31modplugin.h" + +const PluginDescriptor PSK31Plugin::m_pluginDescriptor = { + PSK31::m_channelId, + QStringLiteral("PSK31 Modulator"), + QStringLiteral("7.16.0"), + QStringLiteral("(c) Jon Beniston, M7RCE"), + QStringLiteral("https://github.com/f4exb/sdrangel"), + true, + QStringLiteral("https://github.com/f4exb/sdrangel") +}; + +PSK31Plugin::PSK31Plugin(QObject* parent) : + QObject(parent), + m_pluginAPI(0) +{ +} + +const PluginDescriptor& PSK31Plugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void PSK31Plugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + m_pluginAPI->registerTxChannel(PSK31::m_channelIdURI, PSK31::m_channelId, this); +} + +void PSK31Plugin::createTxChannel(DeviceAPI *deviceAPI, BasebandSampleSource **bs, ChannelAPI **cs) const +{ + if (bs || cs) + { + PSK31 *instance = new PSK31(deviceAPI); + + if (bs) { + *bs = instance; + } + + if (cs) { + *cs = instance; + } + } +} + +#ifdef SERVER_MODE +ChannelGUI* PSK31Plugin::createTxChannelGUI( + DeviceUISet *deviceUISet, + BasebandSampleSource *txChannel) const +{ + (void) deviceUISet; + (void) txChannel; + return nullptr; +} +#else +ChannelGUI* PSK31Plugin::createTxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSource *txChannel) const +{ + return PSK31GUI::create(m_pluginAPI, deviceUISet, txChannel); +} +#endif + +ChannelWebAPIAdapter* PSK31Plugin::createChannelWebAPIAdapter() const +{ + return new PSK31WebAPIAdapter(); +} diff --git a/plugins/channeltx/modpsk31/psk31modplugin.h b/plugins/channeltx/modpsk31/psk31modplugin.h new file mode 100644 index 0000000000..f42c22655e --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modplugin.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2016 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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_PSK31MODPLUGIN_H +#define INCLUDE_PSK31MODPLUGIN_H + +#include +#include "plugin/plugininterface.h" + +class DeviceUISet; +class BasebandSampleSource; + +class PSK31Plugin : public QObject, PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "sdrangel.channeltx.psk31mod") + +public: + explicit PSK31Plugin(QObject* parent = 0); + + const PluginDescriptor& getPluginDescriptor() const; + void initPlugin(PluginAPI* pluginAPI); + + virtual void createTxChannel(DeviceAPI *deviceAPI, BasebandSampleSource **bs, ChannelAPI **cs) const; + virtual ChannelGUI* createTxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSource *rxChannel) const; + virtual ChannelWebAPIAdapter* createChannelWebAPIAdapter() const; + +private: + static const PluginDescriptor m_pluginDescriptor; + + PluginAPI* m_pluginAPI; +}; + +#endif // INCLUDE_PSK31MODPLUGIN_H diff --git a/plugins/channeltx/modpsk31/psk31modrepeatdialog.cpp b/plugins/channeltx/modpsk31/psk31modrepeatdialog.cpp new file mode 100644 index 0000000000..31b63f86ec --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modrepeatdialog.cpp @@ -0,0 +1,43 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 "psk31modrepeatdialog.h" +#include "psk31modsettings.h" +#include + +PSK31RepeatDialog::PSK31RepeatDialog(int repeatCount, QWidget* parent) : + QDialog(parent), + ui(new Ui::PSK31RepeatDialog) +{ + ui->setupUi(this); + QLineEdit *edit = ui->repeatCount->lineEdit(); + if (edit) { + edit->setText(QString("%1").arg(repeatCount)); + } +} + +PSK31RepeatDialog::~PSK31RepeatDialog() +{ + delete ui; +} + +void PSK31RepeatDialog::accept() +{ + QString text = ui->repeatCount->currentText(); + m_repeatCount = text.toUInt(); + QDialog::accept(); +} diff --git a/plugins/channeltx/modpsk31/psk31modrepeatdialog.h b/plugins/channeltx/modpsk31/psk31modrepeatdialog.h new file mode 100644 index 0000000000..626b297bd7 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modrepeatdialog.h @@ -0,0 +1,39 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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_PSK31MODREPEATDIALOG_H +#define INCLUDE_PSK31MODREPEATDIALOG_H + +#include "ui_psk31modrepeatdialog.h" + +class PSK31RepeatDialog : public QDialog { + Q_OBJECT + +public: + explicit PSK31RepeatDialog(int repeatCount, QWidget* parent = 0); + ~PSK31RepeatDialog(); + + int m_repeatCount; // Number of times to transmit + +private slots: + void accept(); + +private: + Ui::PSK31RepeatDialog* ui; +}; + +#endif // INCLUDE_PSK31MODREPEATDIALOG_H diff --git a/plugins/channeltx/modpsk31/psk31modrepeatdialog.ui b/plugins/channeltx/modpsk31/psk31modrepeatdialog.ui new file mode 100644 index 0000000000..d5a6d899a5 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modrepeatdialog.ui @@ -0,0 +1,116 @@ + + + PSK31RepeatDialog + + + + 0 + 0 + 351 + 91 + + + + + Liberation Sans + 9 + + + + Packet Repeat Settings + + + + + + + + + Times to transmit + + + + + + + Number of times to transmit + + + true + + + + 1 + + + + + 10 + + + + + 100 + + + + + 1000 + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + repeatCount + + + + + buttonBox + accepted() + PSK31RepeatDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PSK31RepeatDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/plugins/channeltx/modpsk31/psk31modsettings.cpp b/plugins/channeltx/modpsk31/psk31modsettings.cpp new file mode 100644 index 0000000000..51b7eeba09 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modsettings.cpp @@ -0,0 +1,210 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 "dsp/dspengine.h" +#include "util/baudot.h" +#include "util/simpleserializer.h" +#include "settings/serializable.h" +#include "psk31modsettings.h" + +PSK31Settings::PSK31Settings() : + m_channelMarker(nullptr), + m_rollupState(nullptr) +{ + resetToDefaults(); +} + +void PSK31Settings::resetToDefaults() +{ + m_inputFrequencyOffset = 0; + m_baud = 31.25; + m_rfBandwidth = 100; + m_gain = 0.0f; + m_channelMute = false; + m_repeat = false; + m_repeatCount = 10; + m_lpfTaps = 301; + m_rfNoise = false; + m_text = "CQ CQ CQ DE SDRangel CQ"; + m_prefixCRLF = true; + m_postfixCRLF = true; + m_predefinedTexts = QStringList({ + "CQ CQ CQ DE ${callsign} ${callsign} CQ", + "DE ${callsign} ${callsign} ${callsign}", + "UR 599 QTH IS ${location}", + "TU DE ${callsign} CQ" + }); + m_rgbColor = QColor(25, 180, 200).rgb(); + m_title = "PSK31 Modulator"; + m_streamIndex = 0; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; + m_reverseAPIChannelIndex = 0; + m_pulseShaping = true; + m_beta = 1.0f; + m_symbolSpan = 2; + m_udpEnabled = false; + m_udpAddress = "127.0.0.1"; + m_udpPort = 9998; + m_workspaceIndex = 0; + m_hidden = false; +} + +QByteArray PSK31Settings::serialize() const +{ + SimpleSerializer s(1); + + s.writeS32(1, m_inputFrequencyOffset); + s.writeReal(2, m_baud); + s.writeS32(3, m_rfBandwidth); + s.writeReal(5, m_gain); + s.writeBool(6, m_channelMute); + s.writeBool(7, m_repeat); + s.writeS32(9, m_repeatCount); + s.writeS32(23, m_lpfTaps); + s.writeBool(25, m_rfNoise); + s.writeString(30, m_text); + + s.writeBool(64, m_prefixCRLF); + s.writeBool(65, m_postfixCRLF); + s.writeList(66, m_predefinedTexts); + + s.writeU32(31, m_rgbColor); + s.writeString(32, m_title); + + if (m_channelMarker) { + s.writeBlob(33, m_channelMarker->serialize()); + } + + s.writeS32(34, m_streamIndex); + s.writeBool(35, m_useReverseAPI); + s.writeString(36, m_reverseAPIAddress); + s.writeU32(37, m_reverseAPIPort); + s.writeU32(38, m_reverseAPIDeviceIndex); + s.writeU32(39, m_reverseAPIChannelIndex); + s.writeBool(46, m_pulseShaping); + s.writeReal(47, m_beta); + s.writeS32(48, m_symbolSpan); + s.writeBool(51, m_udpEnabled); + s.writeString(52, m_udpAddress); + s.writeU32(53, m_udpPort); + + if (m_rollupState) { + s.writeBlob(54, m_rollupState->serialize()); + } + + s.writeS32(55, m_workspaceIndex); + s.writeBlob(56, m_geometryBytes); + s.writeBool(57, m_hidden); + + return s.final(); +} + +bool PSK31Settings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if(!d.isValid()) + { + resetToDefaults(); + return false; + } + + if(d.getVersion() == 1) + { + QByteArray bytetmp; + qint32 tmp; + uint32_t utmp; + + d.readS32(1, &tmp, 0); + m_inputFrequencyOffset = tmp; + d.readReal(2, &m_baud, 31.25f); + d.readS32(3, &m_rfBandwidth, 100); + d.readReal(5, &m_gain, 0.0f); + d.readBool(6, &m_channelMute, false); + d.readBool(7, &m_repeat, false); + d.readS32(9, &m_repeatCount, -1); + d.readS32(23, &m_lpfTaps, 301); + d.readBool(25, &m_rfNoise, false); + d.readString(30, &m_text, "CQ CQ CQ anyone using SDRangel"); + + d.readBool(64, &m_prefixCRLF, true); + d.readBool(65, &m_postfixCRLF, true); + d.readList(66, &m_predefinedTexts); + + d.readU32(31, &m_rgbColor); + d.readString(32, &m_title, "PSK31 Modulator"); + + if (m_channelMarker) + { + d.readBlob(33, &bytetmp); + m_channelMarker->deserialize(bytetmp); + } + + d.readS32(34, &m_streamIndex, 0); + d.readBool(35, &m_useReverseAPI, false); + d.readString(36, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(37, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(38, &utmp, 0); + m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; + d.readU32(39, &utmp, 0); + m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readBool(46, &m_pulseShaping, true); + d.readReal(47, &m_beta, 1.0f); + d.readS32(48, &m_symbolSpan, 2); + d.readBool(51, &m_udpEnabled); + d.readString(52, &m_udpAddress, "127.0.0.1"); + d.readU32(53, &utmp); + + if ((utmp > 1023) && (utmp < 65535)) { + m_udpPort = utmp; + } else { + m_udpPort = 9998; + } + + if (m_rollupState) + { + d.readBlob(54, &bytetmp); + m_rollupState->deserialize(bytetmp); + } + + d.readS32(55, &m_workspaceIndex, 0); + d.readBlob(56, &m_geometryBytes); + d.readBool(57, &m_hidden, false); + + return true; + } + else + { + qDebug() << "PSK31Settings::deserialize: ERROR"; + resetToDefaults(); + return false; + } +} diff --git a/plugins/channeltx/modpsk31/psk31modsettings.h b/plugins/channeltx/modpsk31/psk31modsettings.h new file mode 100644 index 0000000000..1a037b9480 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modsettings.h @@ -0,0 +1,73 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 PLUGINS_CHANNELTX_MODPSK31_PSK31MODSETTINGS_H +#define PLUGINS_CHANNELTX_MODPSK31_PSK31MODSETTINGS_H + +#include +#include +#include "dsp/dsptypes.h" +#include "util/baudot.h" + +class Serializable; + +struct PSK31Settings +{ + qint64 m_inputFrequencyOffset; + float m_baud; + int m_rfBandwidth; + Real m_gain; + bool m_channelMute; + bool m_repeat; + int m_repeatCount; + int m_lpfTaps; + bool m_rfNoise; + QString m_text; // Text to send + bool m_pulseShaping; + float m_beta; + int m_symbolSpan; + bool m_prefixCRLF; + bool m_postfixCRLF; + QStringList m_predefinedTexts; + + quint32 m_rgbColor; + QString m_title; + Serializable *m_channelMarker; + int m_streamIndex; + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; + uint16_t m_reverseAPIChannelIndex; + bool m_udpEnabled; + QString m_udpAddress; + uint16_t m_udpPort; + Serializable *m_rollupState; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; + + PSK31Settings(); + void resetToDefaults(); + void setChannelMarker(Serializable *channelMarker) { m_channelMarker = channelMarker; } + void setRollupState(Serializable *rollupState) { m_rollupState = rollupState; } + QByteArray serialize() const; + bool deserialize(const QByteArray& data); +}; + +#endif /* PLUGINS_CHANNELTX_MODPSK31_PSK31MODSETTINGS_H */ diff --git a/plugins/channeltx/modpsk31/psk31modsource.cpp b/plugins/channeltx/modpsk31/psk31modsource.cpp new file mode 100644 index 0000000000..06cde3e3c7 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modsource.cpp @@ -0,0 +1,421 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 "dsp/basebandsamplesink.h" +#include "dsp/datafifo.h" +#include "psk31mod.h" +#include "psk31modsource.h" +#include "util/messagequeue.h" +#include "maincore.h" + +PSK31Source::PSK31Source() : + m_channelSampleRate(48000), + m_channelFrequencyOffset(0), + m_spectrumRate(2000), + m_spectrumSink(nullptr), + m_specSampleBufferIndex(0), + m_magsq(0.0), + m_levelCalcCount(0), + m_peakLevel(0.0f), + m_levelSum(0.0f), + m_byteIdx(0), + m_bitIdx(0), + m_bitCount(0) + { + m_bits.append(0); + m_lowpass.create(301, m_channelSampleRate, 100.0 / 2.0); + m_pulseShape.create(0.5, 6, m_channelSampleRate / 31.25, true); + + m_demodBuffer.resize(1<<12); + m_demodBufferFill = 0; + + m_specSampleBuffer.resize(m_specSampleBufferSize); + m_interpolatorDistanceRemain = 0; + m_interpolatorConsumed = false; + m_interpolatorDistance = (Real)m_channelSampleRate / (Real)m_spectrumRate; + m_interpolator.create(48, m_spectrumRate, m_spectrumRate / 2.2, 3.0); + + applySettings(m_settings, true); + applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); +} + +PSK31Source::~PSK31Source() +{ +} + +void PSK31Source::pull(SampleVector::iterator begin, unsigned int nbSamples) +{ + std::for_each( + begin, + begin + nbSamples, + [this](Sample& s) { + pullOne(s); + } + ); +} + +void PSK31Source::pullOne(Sample& sample) +{ + if (m_settings.m_channelMute) + { + sample.m_real = 0.0f; + sample.m_imag = 0.0f; + return; + } + + // Calculate next sample + modulateSample(); + + // Shift to carrier frequency + Complex ci = m_modSample; + ci *= m_carrierNco.nextIQ(); + + // Calculate power + double magsq = ci.real() * ci.real() + ci.imag() * ci.imag(); + m_movingAverage(magsq); + m_magsq = m_movingAverage.asDouble(); + + // Convert from float to fixed point + sample.m_real = (FixReal) (ci.real() * SDR_TX_SCALEF); + sample.m_imag = (FixReal) (ci.imag() * SDR_TX_SCALEF); +} + +void PSK31Source::sampleToSpectrum(Complex sample) +{ + if (m_spectrumSink) + { + Complex out; + if (m_interpolator.decimate(&m_interpolatorDistanceRemain, sample, &out)) + { + m_interpolatorDistanceRemain += m_interpolatorDistance; + Real r = std::real(out) * SDR_TX_SCALEF; + Real i = std::imag(out) * SDR_TX_SCALEF; + m_specSampleBuffer[m_specSampleBufferIndex++] = Sample(r, i); + if (m_specSampleBufferIndex == m_specSampleBufferSize) + { + m_spectrumSink->feed(m_specSampleBuffer.begin(), m_specSampleBuffer.end(), false); + m_specSampleBufferIndex = 0; + } + } + } +} + +void PSK31Source::modulateSample() +{ + Real mod; + + if (m_sampleIdx == 0) + { + if (m_bitCount == 0) + { + if (!m_textToTransmit.isEmpty()) + { + // Encode a character at a time, so we get a TxReport after each character + QString s = m_textToTransmit.left(1); + m_textToTransmit = m_textToTransmit.mid(1); + encodeText(s); + } + else + { + encodeIdle(); + } + initTX(); + } + + m_bit = getBit(); + + // Differential encoding + m_prevSymbol = m_symbol; + m_symbol = (m_bit ^ m_symbol) ? 0 : 1; + } + + // PSK + if (m_settings.m_pulseShaping) + { + if (m_sampleIdx == 1) { + mod = m_pulseShape.filter(m_symbol ? 1.0f : -1.0f); + } else { + mod = m_pulseShape.filter(0.0f); + } + } + else + { + mod = m_symbol ? 1.0f : -1.0f; + } + + m_sampleIdx++; + if (m_sampleIdx >= m_samplesPerSymbol) { + m_sampleIdx = 0; + } + + if (!m_settings.m_rfNoise) + { + m_modSample.real(m_linearGain * mod); + m_modSample.imag(0.0f); + } + else + { + // Noise to test filter frequency response + m_modSample.real(m_linearGain * ((Real)rand()/((Real)RAND_MAX)-0.5f)); + m_modSample.imag(m_linearGain * ((Real)rand()/((Real)RAND_MAX)-0.5f)); + } + + // Apply low pass filter to limit RF BW + m_modSample = m_lowpass.filter(m_modSample); + + // Display in spectrum analyser + sampleToSpectrum(m_modSample); + + Real s = std::real(m_modSample); + calculateLevel(s); + + // Send to demod analyser + m_demodBuffer[m_demodBufferFill] = mod * std::numeric_limits::max(); + ++m_demodBufferFill; + + if (m_demodBufferFill >= m_demodBuffer.size()) + { + QList dataPipes; + MainCore::instance()->getDataPipes().getDataPipes(m_channel, "demod", dataPipes); + + if (dataPipes.size() > 0) + { + QList::iterator it = dataPipes.begin(); + + for (; it != dataPipes.end(); ++it) + { + DataFifo *fifo = qobject_cast((*it)->m_element); + + if (fifo) { + fifo->write((quint8*) &m_demodBuffer[0], m_demodBuffer.size() * sizeof(qint16), DataFifo::DataTypeI16); + } + } + } + + m_demodBufferFill = 0; + } +} + +void PSK31Source::calculateLevel(Real& sample) +{ + if (m_levelCalcCount < m_levelNbSamples) + { + m_peakLevel = std::max(std::fabs(m_peakLevel), sample); + m_levelSum += sample * sample; + m_levelCalcCount++; + } + else + { + m_rmsLevel = sqrt(m_levelSum / m_levelNbSamples); + m_peakLevelOut = m_peakLevel; + m_peakLevel = 0.0f; + m_levelSum = 0.0f; + m_levelCalcCount = 0; + } +} + +void PSK31Source::applySettings(const PSK31Settings& settings, bool force) +{ + if ((settings.m_baud != m_settings.m_baud) || force) + { + m_samplesPerSymbol = m_channelSampleRate / settings.m_baud; + qDebug() << "m_samplesPerSymbol: " << m_samplesPerSymbol << " (" << m_channelSampleRate << "/" << settings.m_baud << ")"; + } + + if ((settings.m_lpfTaps != m_settings.m_lpfTaps) || (settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) + { + qDebug() << "PSK31Source::applySettings: Creating new lpf with taps " << settings.m_lpfTaps << " rfBW " << settings.m_rfBandwidth; + m_lowpass.create(settings.m_lpfTaps, m_channelSampleRate, settings.m_rfBandwidth / 2.0); + } + if ((settings.m_beta != m_settings.m_beta) || (settings.m_symbolSpan != m_settings.m_symbolSpan) || (settings.m_baud != m_settings.m_baud) || force) + { + qDebug() << "PSK31Source::applySettings: Recreating pulse shaping filter: " + << " beta: " << settings.m_beta + << " symbolSpan: " << settings.m_symbolSpan + << " channelSampleRate:" << m_channelSampleRate + << " baud:" << settings.m_baud; + m_pulseShape.create(settings.m_beta, settings.m_symbolSpan, m_channelSampleRate/settings.m_baud, true); + } + + m_settings = settings; + + m_linearGain = powf(10.0f, m_settings.m_gain/20.0f); +} + +void PSK31Source::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) +{ + qDebug() << "PSK31Source::applyChannelSettings:" + << " channelSampleRate: " << channelSampleRate + << " channelFrequencyOffset: " << channelFrequencyOffset + << " rfBandwidth: " << m_settings.m_rfBandwidth; + + if ((channelFrequencyOffset != m_channelFrequencyOffset) + || (channelSampleRate != m_channelSampleRate) || force) + { + m_carrierNco.setFreq(channelFrequencyOffset, channelSampleRate); + } + + if ((m_channelSampleRate != channelSampleRate) || force) + { + qDebug() << "PSK31Source::applyChannelSettings: Recreating filters"; + m_lowpass.create(m_settings.m_lpfTaps, channelSampleRate, m_settings.m_rfBandwidth / 2.0); + qDebug() << "PSK31Source::applyChannelSettings: Recreating bandpass filter: " + << " channelSampleRate:" << channelSampleRate; + qDebug() << "PSK31Source::applyChannelSettings: Recreating pulse shaping filter: " + << " beta: " << m_settings.m_beta + << " symbolSpan: " << m_settings.m_symbolSpan + << " channelSampleRate:" << m_channelSampleRate + << " baud:" << m_settings.m_baud; + m_pulseShape.create(m_settings.m_beta, m_settings.m_symbolSpan, channelSampleRate/m_settings.m_baud, true); + } + + if ((m_channelSampleRate != channelSampleRate) || force) + { + m_interpolatorDistanceRemain = 0; + m_interpolatorConsumed = false; + m_interpolatorDistance = (Real) channelSampleRate / (Real) m_spectrumRate; + m_interpolator.create(48, m_spectrumRate, m_spectrumRate / 2.2, 3.0); + } + + m_channelSampleRate = channelSampleRate; + m_channelFrequencyOffset = channelFrequencyOffset; + m_samplesPerSymbol = m_channelSampleRate / m_settings.m_baud; + qDebug() << "m_samplesPerSymbol: " << m_samplesPerSymbol << " (" << m_channelSampleRate << "/" << m_settings.m_baud << ")"; + + QList pipes; + MainCore::instance()->getMessagePipes().getMessagePipes(m_channel, "reportdemod", pipes); + + if (pipes.size() > 0) + { + for (const auto& pipe : pipes) + { + MessageQueue* messageQueue = qobject_cast(pipe->m_element); + MainCore::MsgChannelDemodReport *msg = MainCore::MsgChannelDemodReport::create(m_channel, m_channelSampleRate); + messageQueue->push(msg); + } + } +} + +int PSK31Source::getBit() +{ + int bit; + + if (m_bitCount > 0) + { + bit = (m_bits[m_byteIdx] >> m_bitIdx) & 1; + m_bitIdx++; + m_bitCount--; + if (m_bitIdx == 8) + { + m_byteIdx++; + m_bitIdx = 0; + } + } + else + { + qDebug() << "PSK31Source::getBit: Called when empty"; + bit = 1; + } + + return bit; +} + +void PSK31Source::addBit(int bit) +{ + m_bits[m_byteIdx] |= bit << m_bitIdx; + m_bitIdx++; + m_bitCount++; + if (m_bitIdx == 8) + { + m_byteIdx++; + if (m_bits.size() <= m_byteIdx) { + m_bits.append(0); + } + m_bitIdx = 0; + } +} + +void PSK31Source::initTX() +{ + m_byteIdx = 0; + m_bitIdx = 0; +} + +void PSK31Source::addTXText(QString text) +{ + int count = m_settings.m_repeat ? m_settings.m_repeatCount : 1; + + for (int i = 0; i < count; i++) { + + QString s = text; + + if (m_settings.m_prefixCRLF) { + s.prepend("\r\r\n"); + } + if (m_settings.m_postfixCRLF) { + s.append("\r\r\n"); + } + + m_textToTransmit.append(s); + } +} + +void PSK31Source::encodeText(const QString& text) +{ + // PSK31 varicode encoding + m_byteIdx = 0; + m_bitIdx = 0; + m_bitCount = 0; + for (int i = 0; i < m_bits.size(); i++) { + m_bits[i] = 0; + } + + for (int i = 0; i < text.size(); i++) + { + unsigned bits; + unsigned bitCount; + + m_psk31Encoder.encode(text[i], bits, bitCount); + for (unsigned int j = 0; j < bitCount; j++) + { + int txBit = (bits >> j) & 1; + addBit(txBit); + } + } + + if (getMessageQueueToGUI()) + { + PSK31::MsgReportTx* msg = PSK31::MsgReportTx::create(text, m_textToTransmit.size()); + getMessageQueueToGUI()->push(msg); + } +} + +void PSK31Source::encodeIdle() +{ + m_byteIdx = 0; + m_bitIdx = 0; + m_bitCount = 0; + for (int i = 0; i < m_bits.size(); i++) { + m_bits[i] = 0; + } + addBit(0); + addBit(0); +} diff --git a/plugins/channeltx/modpsk31/psk31modsource.h b/plugins/channeltx/modpsk31/psk31modsource.h new file mode 100644 index 0000000000..2c0db32a08 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modsource.h @@ -0,0 +1,133 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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_PSK31MODSOURCE_H +#define INCLUDE_PSK31MODSOURCE_H + +#include +#include +#include + +#include "dsp/channelsamplesource.h" +#include "dsp/nco.h" +#include "dsp/ncof.h" +#include "dsp/interpolator.h" +#include "dsp/firfilter.h" +#include "dsp/raisedcosine.h" +#include "util/movingaverage.h" +#include "util/psk31.h" + +#include "psk31modsettings.h" + +class BasebandSampleSink; +class ChannelAPI; + +class PSK31Source : public ChannelSampleSource +{ +public: + PSK31Source(); + virtual ~PSK31Source(); + + virtual void pull(SampleVector::iterator begin, unsigned int nbSamples); + virtual void pullOne(Sample& sample); + virtual void prefetch(unsigned int nbSamples) { (void) nbSamples; } + + double getMagSq() const { return m_magsq; } + void getLevels(qreal& rmsLevel, qreal& peakLevel, int& numSamples) const + { + rmsLevel = m_rmsLevel; + peakLevel = m_peakLevelOut; + numSamples = m_levelNbSamples; + } + void setMessageQueueToGUI(MessageQueue* messageQueue) { m_messageQueueToGUI = messageQueue; } + void setSpectrumSink(BasebandSampleSink *sampleSink) { m_spectrumSink = sampleSink; } + void applySettings(const PSK31Settings& settings, bool force = false); + void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false); + void addTXText(QString data); + void setChannel(ChannelAPI *channel) { m_channel = channel; } + int getChannelSampleRate() const { return m_channelSampleRate; } + +private: + int m_channelSampleRate; + int m_channelFrequencyOffset; + int m_spectrumRate; + PSK31Settings m_settings; + ChannelAPI *m_channel; + + NCO m_carrierNco; + Real m_linearGain; + Complex m_modSample; + + int m_bit; // Current bit + int m_symbol; // Current symbol + int m_prevSymbol; // Previous symbol for differential encoding + RaisedCosine m_pulseShape; // Pulse shaping filter + Lowpass m_lowpass; // Low pass filter to limit RF bandwidth + + BasebandSampleSink* m_spectrumSink; // Spectrum GUI to display baseband waveform + SampleVector m_specSampleBuffer; + static const int m_specSampleBufferSize = 256; + int m_specSampleBufferIndex; + Interpolator m_interpolator; // Interpolator to downsample to spectrum + Real m_interpolatorDistance; + Real m_interpolatorDistanceRemain; + bool m_interpolatorConsumed; + + double m_magsq; + MovingAverageUtil m_movingAverage; + + quint32 m_levelCalcCount; + qreal m_rmsLevel; + qreal m_peakLevelOut; + Real m_peakLevel; + Real m_levelSum; + + static const int m_levelNbSamples = 480; // every 10ms assuming 48k Sa/s + + int m_sampleIdx; // Sample index in to symbol + int m_samplesPerSymbol; // Number of samples per symbol + + QString m_textToTransmit; // Transmit buffer (before encoding) + + PSK31Encoder m_psk31Encoder; + + QList m_bits; // Bits to transmit + int m_byteIdx; // Index in to m_bits + int m_bitIdx; // Index in to current byte of m_bits + int m_bitCount; // Count of number of valid bits in m_bits + + QVector m_demodBuffer; + int m_demodBufferFill; + + MessageQueue* m_messageQueueToGUI; + + MessageQueue* getMessageQueueToGUI() { return m_messageQueueToGUI; } + + void encodeText(const QString& data); + void encodeIdle(); + int getBit(); // Get bit from m_bits + void addBit(int bit); // Add bit to m_bits, with zero stuffing + void initTX(); + + void calculateLevel(Real& sample); + void modulateSample(); + void sampleToSpectrum(Complex sample); + +}; + +#endif // INCLUDE_PSK31MODSOURCE_H diff --git a/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.cpp b/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.cpp new file mode 100644 index 0000000000..9b250e828e --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.cpp @@ -0,0 +1,110 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 "psk31modtxsettingsdialog.h" + +static QListWidgetItem* newItem(const QString& text) +{ + QListWidgetItem* item = new QListWidgetItem(text); + item->setFlags(item->flags() | Qt::ItemIsEditable); + return item; +} + +PSK31TXSettingsDialog::PSK31TXSettingsDialog(PSK31Settings* settings, QWidget *parent) : + QDialog(parent), + m_settings(settings), + ui(new Ui::PSK31TXSettingsDialog) +{ + ui->setupUi(this); + ui->prefixCRLF->setChecked(m_settings->m_prefixCRLF); + ui->postfixCRLF->setChecked(m_settings->m_postfixCRLF); + for (const auto& text : m_settings->m_predefinedTexts) { + ui->predefinedText->addItem(newItem(text)); + } + ui->pulseShaping->setChecked(m_settings->m_pulseShaping); + ui->beta->setValue(m_settings->m_beta); + ui->symbolSpan->setValue(m_settings->m_symbolSpan); + ui->lpfTaps->setValue(m_settings->m_lpfTaps); + ui->rfNoise->setChecked(m_settings->m_rfNoise); +} + +PSK31TXSettingsDialog::~PSK31TXSettingsDialog() +{ + delete ui; +} + +void PSK31TXSettingsDialog::accept() +{ + m_settings->m_prefixCRLF = ui->prefixCRLF->isChecked(); + m_settings->m_postfixCRLF = ui->postfixCRLF->isChecked(); + m_settings->m_predefinedTexts.clear(); + for (int i = 0; i < ui->predefinedText->count(); i++) { + m_settings->m_predefinedTexts.append(ui->predefinedText->item(i)->text()); + } + m_settings->m_pulseShaping = ui->pulseShaping->isChecked(); + m_settings->m_beta = ui->beta->value(); + m_settings->m_symbolSpan = ui->symbolSpan->value(); + m_settings->m_lpfTaps = ui->lpfTaps->value(); + m_settings->m_rfNoise = ui->rfNoise->isChecked(); + + QDialog::accept(); +} + +void PSK31TXSettingsDialog::on_add_clicked() +{ + QListWidgetItem* item = newItem("..."); + ui->predefinedText->addItem(item); + ui->predefinedText->setCurrentItem(item); +} + +void PSK31TXSettingsDialog::on_remove_clicked() +{ + QList items = ui->predefinedText->selectedItems(); + for (auto item : items) { + delete ui->predefinedText->takeItem(ui->predefinedText->row(item)); + } +} + +void PSK31TXSettingsDialog::on_up_clicked() +{ + QList items = ui->predefinedText->selectedItems(); + for (auto item : items) + { + int row = ui->predefinedText->row(item); + if (row > 0) + { + QListWidgetItem* item = ui->predefinedText->takeItem(row); + ui->predefinedText->insertItem(row - 1, item); + ui->predefinedText->setCurrentItem(item); + } + } +} + +void PSK31TXSettingsDialog::on_down_clicked() +{ + QList items = ui->predefinedText->selectedItems(); + for (auto item : items) + { + int row = ui->predefinedText->row(item); + if (row < ui->predefinedText->count() - 1) + { + QListWidgetItem* item = ui->predefinedText->takeItem(row); + ui->predefinedText->insertItem(row + 1, item); + ui->predefinedText->setCurrentItem(item); + } + } +} diff --git a/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.h b/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.h new file mode 100644 index 0000000000..c47d25f595 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.h @@ -0,0 +1,44 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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_PSK31MODTXSETTINGSDIALOG_H +#define INCLUDE_PSK31MODTXSETTINGSDIALOG_H + +#include "ui_psk31modtxsettingsdialog.h" +#include "psk31modsettings.h" + +class PSK31TXSettingsDialog : public QDialog { + Q_OBJECT + +public: + explicit PSK31TXSettingsDialog(PSK31Settings *settings, QWidget *parent = nullptr); + ~PSK31TXSettingsDialog(); + + PSK31Settings *m_settings; + +private slots: + void accept(); + void on_add_clicked(); + void on_remove_clicked(); + void on_up_clicked(); + void on_down_clicked(); + +private: + Ui::PSK31TXSettingsDialog* ui; +}; + +#endif // INCLUDE_PSK31MODTXSETTINGSDIALOG_H diff --git a/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.ui b/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.ui new file mode 100644 index 0000000000..31f63eb676 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modtxsettingsdialog.ui @@ -0,0 +1,284 @@ + + + PSK31TXSettingsDialog + + + + 0 + 0 + 351 + 554 + + + + + Liberation Sans + 9 + + + + Transmit Settings + + + + + + Text + + + + + + Prefix text with carriage returns and line feed + + + Prefix CR+CR+LF + + + + + + + Predefined text + + + + + + + + + + 22 + 22 + + + + Add item to list + + + + + + + + + + + + 22 + 22 + + + + Remove selected items from list + + + - + + + + + + + Move selected item up + + + Up + + + + :/arrow_up.png:/arrow_up.png + + + + + + + Move selected item down + + + + + + + :/arrow_down.png:/arrow_down.png + + + + + + + + + Postfix text with carriage returns and line feeds + + + Postfix CR+CR+LF + + + + + + + Predefined text messages + +Substitutions: +${callsign} +${location} + + + QAbstractItemView::InternalMove + + + Qt::MoveAction + + + + + + + + + + Modulation + + + + + + RF BW limit LPF taps + + + + + + + Number of taps in LPF for RF BW filter. + + + 10000 + + + + + + + Enable raised cosine pulse shaping filter + + + Raised cosine pulse shaping + + + + + + + Filter rolloff (beta) + + + + + + + Roll-off of the filter + + + 1.000000000000000 + + + 0.250000000000000 + + + + + + + Filter symbol span + + + + + + + Number of symbols over which filter is applied + + + 1 + + + 20 + + + + + + + + + + Debug + + + + + + Generate white noise as RF signal. + + + Generate RF noise + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + PSK31TXSettingsDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PSK31TXSettingsDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/plugins/channeltx/modpsk31/psk31modwebapiadapter.cpp b/plugins/channeltx/modpsk31/psk31modwebapiadapter.cpp new file mode 100644 index 0000000000..349526654b --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modwebapiadapter.cpp @@ -0,0 +1,53 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB. // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 "SWGChannelSettings.h" +#include "psk31mod.h" +#include "psk31modwebapiadapter.h" + +PSK31WebAPIAdapter::PSK31WebAPIAdapter() +{} + +PSK31WebAPIAdapter::~PSK31WebAPIAdapter() +{} + +int PSK31WebAPIAdapter::webapiSettingsGet( + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setPsk31ModSettings(new SWGSDRangel::SWGPSK31ModSettings()); + response.getPsk31ModSettings()->init(); + PSK31::webapiFormatChannelSettings(response, m_settings); + + return 200; +} + +int PSK31WebAPIAdapter::webapiSettingsPutPatch( + bool force, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage) +{ + (void) force; // no action + (void) errorMessage; + PSK31::webapiUpdateChannelSettings(m_settings, channelSettingsKeys, response); + + PSK31::webapiFormatChannelSettings(response, m_settings); + return 200; +} diff --git a/plugins/channeltx/modpsk31/psk31modwebapiadapter.h b/plugins/channeltx/modpsk31/psk31modwebapiadapter.h new file mode 100644 index 0000000000..3709ee4f70 --- /dev/null +++ b/plugins/channeltx/modpsk31/psk31modwebapiadapter.h @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB. // +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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_PSK31MOD_WEBAPIADAPTER_H +#define INCLUDE_PSK31MOD_WEBAPIADAPTER_H + +#include "channel/channelwebapiadapter.h" +#include "psk31modsettings.h" + +/** + * Standalone API adapter only for the settings + */ +class PSK31WebAPIAdapter : public ChannelWebAPIAdapter { +public: + PSK31WebAPIAdapter(); + virtual ~PSK31WebAPIAdapter(); + + virtual QByteArray serialize() const { return m_settings.serialize(); } + virtual bool deserialize(const QByteArray& data) { return m_settings.deserialize(data); } + + virtual int webapiSettingsGet( + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage); + +private: + PSK31Settings m_settings; +}; + +#endif // INCLUDE_PSK31MOD_WEBAPIADAPTER_H diff --git a/plugins/channeltx/modpsk31/readme.md b/plugins/channeltx/modpsk31/readme.md new file mode 100644 index 0000000000..31fa1eecb6 --- /dev/null +++ b/plugins/channeltx/modpsk31/readme.md @@ -0,0 +1,101 @@ +

PSK31 Modulator Plugin

+ +

Introduction

+ +This plugin can be used to modulate PSK31 encoded text. +PSK31 uses differential Binary Phase Shift Keying at 31.25 baud. + +

Interface

+ +The top and bottom bars of the channel window are described [here](../../../sdrgui/channel/readme.md) + +![PSK31 Modulator plugin GUI](../../../doc/img/PSK31Mod_plugin.png) + +

1: Frequency shift from center frequency of transmission

+ +Use the wheels to adjust the frequency shift in Hz from the center frequency of transmission. Left click on a digit sets the cursor position at this digit. Right click on a digit sets all digits on the right to zero. This effectively floors value at the digit position. Wheels are moved with the mousewheel while pointing at the wheel or by selecting the wheel with the left mouse click and using the keyboard arrows. Pressing shift simultaneously moves digit by 5 and pressing control moves it by 2. + +

2: Channel power

+ +Average total power in dB relative to a +/- 1.0 amplitude signal generated in the pass band. + +

3: Channel mute

+ +Use this button to toggle mute for this channel. + +

4: RF Bandwidth

+ +This specifies the bandwidth of a LPF that is applied to the output signal to limit the RF bandwidth. + +

5: Gain

+ +Adjusts the gain in dB from -60 to 0dB. + +

6: Level meter in %

+ + - top bar (beige): average value + - bottom bar (brown): instantaneous peak value + - tip vertical bar (bright red): peak hold value + +

7: UDP

+ +When checked, a UDP port is opened to receive text from other features or applications that will be transmitted. + +

8: UDP address

+ +IP address of the interface to open the UDP port on, to receive text to be transmitted. + +

9: UDP port

+ +UDP port number to receive text to be transmitted on. + +

10: Repeat

+ +Check this button to repeatedly transmit a text message. Right click to open the dialog to adjust the number of times the text should be repeated. + +

11: Clear Transmitted Text

+ +Press to clear the transmitted text. + +

12: Text to Transmit

+ +Enter text to transmit. Pressing return will transmit the text and clear this field. Press the arrow to display and select a list of pre-defined text or previously transmitted text to enter in to the field. + +The list of pre-defined text can be customised via the Transmit Settings dialog (13). + +PSK31 supports the extended ASCII character set. + +

13: TX

+ +Press to transmit the current text. The text field will not be cleared. + +Right click to open a dialog to adjust additional Transmit Settings, including the list of pre-defined text. + +Predefined text supports the following variable substitutions: + +* ${callsign} - Gets replaced with the station name from Preferences > My Position +* ${location} = Gets replaced with the Maidenhead locator for the position specified under Preferences > My Position + +The substitutions are applied when the Transmit Settings dialog is closed. + +

14: Transmitted Text

+ +The trasnmitted text area shows characters as they are transmitted. + +Holding the cursor over an acronym may show a tooltip with the decoded acronym. + +

API

+ +Full details of the API can be found in the Swagger documentation. Below are a few examples. + +To transmit the current text simply send a "tx" action: + + curl -X POST "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/actions" -d '{"channelType": "PSK31Mod", "direction": 1, "PSK31ModActions": { "tx": 1 }}' + +To transmit text specified on the command line: + + curl -X POST "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/actions" -d '{"channelType": "PSK31Mod", "direction": 1, "PSK31ModActions": { "tx": 1, "payload": {"text": "CQ CQ CQ anyone using SDRangel CQ" }}}' + +To adjust a setting, such as the frequency offset: + + curl -X PATCH "http://127.0.0.1:8091/sdrangel/deviceset/0/channel/0/settings" -d '{"channelType": "PSK31Mod", "direction": 1, "PSK31ModSettings": {"inputFrequencyOffset": 2000 }}' diff --git a/plugins/channeltx/modrtty/rttymodgui.cpp b/plugins/channeltx/modrtty/rttymodgui.cpp index f1fc898ea9..fc710af256 100644 --- a/plugins/channeltx/modrtty/rttymodgui.cpp +++ b/plugins/channeltx/modrtty/rttymodgui.cpp @@ -264,6 +264,12 @@ void RttyModGUI::on_spaceHigh_clicked(bool checked) applySettings(); } +void RttyModGUI::on_unshiftOnSpace_clicked(bool checked) +{ + m_settings.m_unshiftOnSpace = checked; + applySettings(); +} + void RttyModGUI::on_clearTransmittedText_clicked() { ui->transmittedText->clear(); @@ -567,7 +573,6 @@ void RttyModGUI::displaySettings() ui->baudRate->setCurrentIndex(ui->baudRate->findText(baudRate)); ui->frequencyShiftText->setText(formatFrequency(m_settings.m_frequencyShift)); ui->frequencyShift->setValue(m_settings.m_frequencyShift); - ui->frequencyShift->setValue(m_settings.m_frequencyShift); ui->characterSet->setCurrentIndex((int)m_settings.m_characterSet); ui->endian->setChecked(m_settings.m_msbFirst); @@ -582,12 +587,13 @@ void RttyModGUI::displaySettings() } else { ui->spaceHigh->setText("S-M"); } + ui->unshiftOnSpace->setChecked(m_settings.m_unshiftOnSpace); ui->udpEnabled->setChecked(m_settings.m_udpEnabled); ui->udpAddress->setText(m_settings.m_udpAddress); ui->udpPort->setText(QString::number(m_settings.m_udpPort)); - ui->gainText->setText(QString("%1").arg((double)m_settings.m_gain, 0, 'f', 1)); + ui->gainText->setText(QString("%1dB").arg((double)m_settings.m_gain, 0, 'f', 1)); ui->gain->setValue(m_settings.m_gain); ui->channelMute->setChecked(m_settings.m_channelMute); @@ -633,6 +639,7 @@ void RttyModGUI::makeUIConnections() QObject::connect(ui->characterSet, QOverload::of(&QComboBox::currentIndexChanged), this, &RttyModGUI::on_characterSet_currentIndexChanged); QObject::connect(ui->endian, &QCheckBox::clicked, this, &RttyModGUI::on_endian_clicked); QObject::connect(ui->spaceHigh, &QCheckBox::clicked, this, &RttyModGUI::on_spaceHigh_clicked); + QObject::connect(ui->unshiftOnSpace, &QCheckBox::clicked, this, &RttyModGUI::on_unshiftOnSpace_clicked); QObject::connect(ui->clearTransmittedText, &QToolButton::clicked, this, &RttyModGUI::on_clearTransmittedText_clicked); QObject::connect(ui->gain, &QDial::valueChanged, this, &RttyModGUI::on_gain_valueChanged); QObject::connect(ui->channelMute, &QToolButton::toggled, this, &RttyModGUI::on_channelMute_toggled); diff --git a/plugins/channeltx/modrtty/rttymodgui.h b/plugins/channeltx/modrtty/rttymodgui.h index 1e79e34633..65120cfd80 100644 --- a/plugins/channeltx/modrtty/rttymodgui.h +++ b/plugins/channeltx/modrtty/rttymodgui.h @@ -77,7 +77,7 @@ public slots: QString m_initialToolTip; RttyMod* m_rttyMod; - MovingAverageUtil m_channelPowerDbAvg; // Less than other mods, as packets are short + MovingAverageUtil m_channelPowerDbAvg; MessageQueue m_inputMessageQueue; @@ -110,6 +110,7 @@ private slots: void on_characterSet_currentIndexChanged(int index); void on_endian_clicked(bool checked); void on_spaceHigh_clicked(bool checked); + void on_unshiftOnSpace_clicked(bool checked); void on_clearTransmittedText_clicked(); void on_txButton_clicked(); void on_text_editingFinished(); diff --git a/plugins/channeltx/modrtty/rttymodsettings.cpp b/plugins/channeltx/modrtty/rttymodsettings.cpp index d6682c26a4..140eb9625d 100644 --- a/plugins/channeltx/modrtty/rttymodsettings.cpp +++ b/plugins/channeltx/modrtty/rttymodsettings.cpp @@ -44,9 +44,9 @@ void RttyModSettings::resetToDefaults() m_repeatCount = 10; m_lpfTaps = 301; m_rfNoise = false; - m_writeToFile = false; m_text = "CQ CQ CQ DE SDRangel CQ"; m_characterSet = Baudot::ITA2; + m_unshiftOnSpace = false; m_msbFirst = false; m_spaceHigh = false; m_prefixCRLF = true; @@ -94,7 +94,6 @@ QByteArray RttyModSettings::serialize() const s.writeS32(9, m_repeatCount); s.writeS32(23, m_lpfTaps); s.writeBool(25, m_rfNoise); - s.writeBool(26, m_writeToFile); s.writeString(30, m_text); s.writeS32(60, (int)m_characterSet); @@ -164,7 +163,6 @@ bool RttyModSettings::deserialize(const QByteArray& data) d.readS32(9, &m_repeatCount, -1); d.readS32(23, &m_lpfTaps, 301); d.readBool(25, &m_rfNoise, false); - d.readBool(26, &m_writeToFile, false); d.readString(30, &m_text, "CQ CQ CQ anyone using SDRangel"); d.readS32(60, (int*)&m_characterSet, (int)Baudot::ITA2); diff --git a/plugins/feature/demodanalyzer/demodanalyzersettings.cpp b/plugins/feature/demodanalyzer/demodanalyzersettings.cpp index f7a21d5039..3ebb933e41 100644 --- a/plugins/feature/demodanalyzer/demodanalyzersettings.cpp +++ b/plugins/feature/demodanalyzer/demodanalyzersettings.cpp @@ -38,6 +38,7 @@ const QStringList DemodAnalyzerSettings::m_channelTypes = { QStringLiteral("PacketDemod"), QStringLiteral("PacketMod"), QStringLiteral("RadiosondeDemod"), + QStringLiteral("PSK31Mod"), QStringLiteral("RTTYMod"), QStringLiteral("SSBDemod"), QStringLiteral("SSBMod"), @@ -61,6 +62,7 @@ const QStringList DemodAnalyzerSettings::m_channelURIs = { QStringLiteral("sdrangel.channel.packetdemod"), QStringLiteral("sdrangel.channeltx.modpacket"), QStringLiteral("sdrangel.channel.radiosondedemod"), + QStringLiteral("sdrangel.channeltx.modpsk31"), QStringLiteral("sdrangel.channeltx.modrtty"), QStringLiteral("sdrangel.channel.ssbdemod"), QStringLiteral("sdrangel.channeltx.modssb"), diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index 63f0ed392a..09ded39139 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -252,6 +252,7 @@ set(sdrbase_SOURCES util/png.cpp util/prettyprint.cpp util/profiler.cpp + util/psk31.cpp util/radiosonde.cpp util/rtpsink.cpp util/syncmessenger.cpp @@ -491,6 +492,7 @@ set(sdrbase_HEADERS util/png.h util/prettyprint.h util/profiler.h + util/psk31.h util/radiosonde.h util/rtpsink.h util/rtty.h diff --git a/sdrbase/util/psk31.cpp b/sdrbase/util/psk31.cpp new file mode 100644 index 0000000000..731410711b --- /dev/null +++ b/sdrbase/util/psk31.cpp @@ -0,0 +1,329 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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 "psk31.h" + +// ASCII varicode encoding +// From http://www.aintel.bi.ehu.es/psk31.html +const QStringList PSK31Varicode::m_varicode = { + "1010101011", + "1011011011", + "1011101101", + "1101110111", + "1011101011", + "1101011111", + "1011101111", + "1011111101", + "1011111111", + "11101111", + "11101", + "1101101111", + "1011011101", + "11111", + "1101110101", + "1110101011", + "1011110111", + "1011110101", + "1110101101", + "1110101111", + "1101011011", + "1101101011", + "1101101101", + "1101010111", + "1101111011", + "1101111101", + "1110110111", + "1101010101", + "1101011101", + "1110111011", + "1011111011", + "1101111111", + "1", + "111111111", + "101011111", + "111110101", + "111011011", + "1011010101", + "1010111011", + "101111111", + "11111011", + "11110111", + "101101111", + "111011111", + "1110101", + "110101", + "1010111", + "110101111", + "10110111", + "10111101", + "11101101", + "11111111", + "101110111", + "101011011", + "101101011", + "110101101", + "110101011", + "110110111", + "11110101", + "110111101", + "111101101", + "1010101", + "111010111", + "1010101111", + "1010111101", + "1111101", + "11101011", + "10101101", + "10110101", + "1110111", + "11011011", + "11111101", + "101010101", + "1111111", + "111111101", + "101111101", + "11010111", + "10111011", + "11011101", + "10101011", + "11010101", + "111011101", + "10101111", + "1101111", + "1101101", + "101010111", + "110110101", + "101011101", + "101110101", + "101111011", + "1010101101", + "111110111", + "111101111", + "111111011", + "1010111111", + "101101101", + "1011011111", + "1011", + "1011111", + "101111", + "101101", + "11", + "111101", + "1011011", + "101011", + "1101", + "111101011", + "10111111", + "11011", + "111011", + "1111", + "111", + "111111", + "110111111", + "10101", + "10111", + "101", + "110111", + "1111011", + "1101011", + "11011111", + "1011101", + "111010101", + "1010110111", + "110111011", + "1010110101", + "1011010111", + "1110110101", + "1110111101", + "1110111111", + "1111010101", + "1111010111", + "1111011011", + "1111011101", + "1111011111", + "1111101011", + "1111101101", + "1111101111", + "1111110101", + "1111110111", + "1111111011", + "1111111101", + "1111111111", + "10101010101", + "10101010111", + "10101011011", + "10101011101", + "10101011111", + "10101101011", + "10101101101", + "10101101111", + "10101110101", + "10101110111", + "10101111011", + "10101111101", + "10101111111", + "10110101011", + "10110101101", + "10110101111", + "10110110101", + "10110110111", + "10110111011", + "10110111101", + "10110111111", + "10111010101", + "10111010111", + "10111011011", + "10111011101", + "10111011111", + "10111101011", + "10111101101", + "10111101111", + "10111110101", + "10111110111", + "10111111011", + "10111111101", + "10111111111", + "11010101011", + "11010101101", + "11010101111", + "11010110101", + "11010110111", + "11010111011", + "11010111101", + "11010111111", + "11011010101", + "11011010111", + "11011011011", + "11011011101", + "11011011111", + "11011101011", + "11011101101", + "11011101111", + "11011110101", + "11011110111", + "11011111011", + "11011111101", + "11011111111", + "11101010101", + "11101010111", + "11101011011", + "11101011101", + "11101011111", + "11101101011", + "11101101101", + "11101101111", + "11101110101", + "11101110111", + "11101111011", + "11101111101", + "11101111111", + "11110101011", + "11110101101", + "11110101111", + "11110110101", + "11110110111", + "11110111011", + "11110111101", + "11110111111", + "11111010101", + "11111010111", + "11111011011", + "11111011101", + "11111011111", + "11111101011", + "11111101101", + "11111101111", + "11111110101", + "11111110111", + "11111111011", + "11111111101", + "11111111111", + "101010101011", + "101010101101", + "101010101111", + "101010110101", + "101010110111", + "101010111011", + "101010111101", + "101010111111", + "101011010101", + "101011010111", + "101011011011", + "101011011101", + "101011011111", + "101011101011", + "101011101101", + "101011101111", + "101011110101", + "101011110111", + "101011111011", + "101011111101", + "101011111111", + "101101010101", + "101101010111", + "101101011011" +}; + +PSK31Encoder::PSK31Encoder() +{ +} + +bool PSK31Encoder::encode(QChar c, unsigned &bits, unsigned int &bitCount) +{ + bits = 0; + bitCount = 0; + + unsigned char ch = (unsigned char) c.toLatin1(); + QString code = PSK31Varicode::m_varicode[ch]; + + addCode(bits, bitCount, code); + return true; +} + +void PSK31Encoder::addCode(unsigned& bits, unsigned int& bitCount, const QString& code) const +{ + int codeBits = 0; + unsigned int codeLen = code.size(); + + for (unsigned int i = 0; i < codeLen; i++) { + codeBits |= (code[i] == "1" ? 1 : 0) << i; + } + + addStartBits(bits, bitCount); + addBits(bits, bitCount, codeBits, codeLen); + addStopBits(bits, bitCount); +} + +void PSK31Encoder::addStartBits(unsigned& bits, unsigned int& bitCount) const +{ + // Start bit is 0 + addBits(bits, bitCount, 0, 1); +} + +void PSK31Encoder::addStopBits(unsigned& bits, unsigned int& bitCount) const +{ + // Stop bit is 0 + addBits(bits, bitCount, 0, 1); +} + +void PSK31Encoder::addBits(unsigned& bits, unsigned int& bitCount, int data, int count) const +{ + bits |= data << bitCount; + bitCount += count; +} diff --git a/sdrbase/util/psk31.h b/sdrbase/util/psk31.h new file mode 100644 index 0000000000..1b21069bac --- /dev/null +++ b/sdrbase/util/psk31.h @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 Jon Beniston, M7RCE // +// // +// 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_UTIL_PSK31_H +#define INCLUDE_UTIL_PSK31_H + +#include + +#include "export.h" + +class SDRBASE_API PSK31Varicode { + +public: + + static const QStringList m_varicode; // Index with 8-bit extended-ASCII + +}; + +class SDRBASE_API PSK31Encoder { + +public: + + PSK31Encoder(); + bool encode(QChar c, unsigned& bits, unsigned int &bitCount); + +private: + + void addCode(unsigned& bits, unsigned int& bitCount, const QString& code) const; + void addStartBits(unsigned int& bits, unsigned int& bitCount) const; + void addStopBits(unsigned int& bits, unsigned int& bitCount) const; + void addBits(unsigned int& bits, unsigned int& bitCount, int data, int count) const; + +}; + +#endif // INCLUDE_UTIL_PSK31_H + diff --git a/sdrbase/webapi/webapirequestmapper.cpp b/sdrbase/webapi/webapirequestmapper.cpp index 7670da0099..4254a0473a 100644 --- a/sdrbase/webapi/webapirequestmapper.cpp +++ b/sdrbase/webapi/webapirequestmapper.cpp @@ -4609,6 +4609,11 @@ bool WebAPIRequestMapper::getChannelSettings( channelSettings->setPagerDemodSettings(new SWGSDRangel::SWGPagerDemodSettings()); channelSettings->getPagerDemodSettings()->fromJsonObject(settingsJsonObject); } + else if (channelSettingsKey == "PSK31ModSettings") + { + channelSettings->setPsk31ModSettings(new SWGSDRangel::SWGPSK31ModSettings()); + channelSettings->getPsk31ModSettings()->fromJsonObject(settingsJsonObject); + } else if (channelSettingsKey == "RadioAstronomySettings") { channelSettings->setRadioAstronomySettings(new SWGSDRangel::SWGRadioAstronomySettings()); @@ -4643,12 +4648,12 @@ bool WebAPIRequestMapper::getChannelSettings( { channelSettings->setRttyDemodSettings(new SWGSDRangel::SWGRTTYDemodSettings()); channelSettings->getRttyDemodSettings()->fromJsonObject(settingsJsonObject); - } + } else if (channelSettingsKey == "RTTYModSettings") { channelSettings->setRttyModSettings(new SWGSDRangel::SWGRTTYModSettings()); channelSettings->getRttyModSettings()->fromJsonObject(settingsJsonObject); - } + } else if (channelSettingsKey == "SigMFFileSinkSettings") { channelSettings->setSigMfFileSinkSettings(new SWGSDRangel::SWGSigMFFileSinkSettings()); @@ -4756,6 +4761,11 @@ bool WebAPIRequestMapper::getChannelActions( channelActions->setPacketModActions(new SWGSDRangel::SWGPacketModActions()); channelActions->getPacketModActions()->fromJsonObject(actionsJsonObject); } + else if (channelActionsKey == "PSK31ModActions") + { + channelActions->setPsk31ModActions(new SWGSDRangel::SWGPSK31ModActions()); + channelActions->getPsk31ModActions()->fromJsonObject(actionsJsonObject); + } else if (channelActionsKey == "RTTYModActions") { channelActions->setRttyModActions(new SWGSDRangel::SWGRTTYModActions()); @@ -5435,6 +5445,7 @@ void WebAPIRequestMapper::resetChannelSettings(SWGSDRangel::SWGChannelSettings& channelSettings.setPacketDemodSettings(nullptr); channelSettings.setPacketModSettings(nullptr); channelSettings.setPagerDemodSettings(nullptr); + channelSettings.setPsk31ModSettings(nullptr); channelSettings.setRadioAstronomySettings(nullptr); channelSettings.setRadioClockSettings(nullptr); channelSettings.setRadiosondeDemodSettings(nullptr); @@ -5474,6 +5485,7 @@ void WebAPIRequestMapper::resetChannelReport(SWGSDRangel::SWGChannelReport& chan channelReport.setNoiseFigureReport(nullptr); channelReport.setIeee802154ModReport(nullptr); channelReport.setPacketModReport(nullptr); + channelReport.setPsk31ModReport(nullptr); channelReport.setRadioAstronomyReport(nullptr); channelReport.setRadioClockReport(nullptr); channelReport.setRadiosondeDemodReport(nullptr); @@ -5498,8 +5510,9 @@ void WebAPIRequestMapper::resetChannelActions(SWGSDRangel::SWGChannelActions& ch channelActions.setChannelType(nullptr); channelActions.setFileSourceActions(nullptr); channelActions.setIeee802154ModActions(nullptr); - channelActions.setRadioAstronomyActions(nullptr); channelActions.setPacketModActions(nullptr); + channelActions.setPsk31ModActions(nullptr); + channelActions.setRadioAstronomyActions(nullptr); channelActions.setRttyModActions(nullptr); } diff --git a/sdrbase/webapi/webapiutils.cpp b/sdrbase/webapi/webapiutils.cpp index e9fa38d31b..03f02df4eb 100644 --- a/sdrbase/webapi/webapiutils.cpp +++ b/sdrbase/webapi/webapiutils.cpp @@ -63,6 +63,7 @@ const QMap WebAPIUtils::m_channelURIToSettingsKey = { {"sdrangel.channel.packetdemod", "PacketDemodSettings"}, {"sdrangel.channel.pagerdemod", "PagerDemodSettings"}, {"sdrangel.channeltx.modpacket", "PacketModSettings"}, + {"sdrangel.channel.psk31mod", "PSK31ModSettings"}, {"sdrangel.channeltx.mod802.15.4", "IEEE_802_15_4_ModSettings"}, {"sdrangel.channel.radioclock", "RadioClockSettings"}, {"sdrangel.channel.radiosondedemod", "RadiosondeDemodSettings"}, @@ -178,6 +179,7 @@ const QMap WebAPIUtils::m_channelTypeToSettingsKey = { {"PacketDemod", "PacketDemodSettings"}, {"PacketMod", "PacketModSettings"}, {"PagerDemod", "PagerDemodSettings"}, + {"PSK31Mod", "PSK31ModSettings"}, {"LocalSink", "LocalSinkSettings"}, {"LocalSource", "LocalSourceSettings"}, {"RadioAstronomy", "RadioAstronomySettings"}, @@ -211,6 +213,7 @@ const QMap WebAPIUtils::m_channelTypeToActionsKey = { {"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModActions"}, {"RadioAstronomy", "RadioAstronomyActions"}, {"PacketMod", "PacketModActions"}, + {"PSK31Mod", "PSK31ModActions"}, {"RTTYMod", "RTTYModActions"} }; diff --git a/swagger/sdrangel/api/swagger/include/ChannelActions.yaml b/swagger/sdrangel/api/swagger/include/ChannelActions.yaml index 7eee32cf5e..d0cad67df2 100644 --- a/swagger/sdrangel/api/swagger/include/ChannelActions.yaml +++ b/swagger/sdrangel/api/swagger/include/ChannelActions.yaml @@ -29,6 +29,8 @@ ChannelActions: $ref: "http://swgserver:8081/api/swagger/include/IEEE_802_15_4_Mod.yaml#/IEEE_802_15_4_ModActions" PacketModActions: $ref: "http://swgserver:8081/api/swagger/include/PacketMod.yaml#/PacketModActions" + PSK31ModActions: + $ref: "http://swgserver:8081/api/swagger/include/PSK31Mod.yaml#/PSK31ModActions" RadioAstronomyActions: $ref: "http://swgserver:8081/api/swagger/include/RadioAstronomy.yaml#/RadioAstronomyActions" RTTYModActions: diff --git a/swagger/sdrangel/api/swagger/include/ChannelReport.yaml b/swagger/sdrangel/api/swagger/include/ChannelReport.yaml index 5f8e9038b4..01b5d29b80 100644 --- a/swagger/sdrangel/api/swagger/include/ChannelReport.yaml +++ b/swagger/sdrangel/api/swagger/include/ChannelReport.yaml @@ -53,8 +53,6 @@ ChannelReport: $ref: "http://swgserver:8081/api/swagger/include/FreqTracker.yaml#/FreqTrackerReport" FT8DemodReport: $ref: "http://swgserver:8081/api/swagger/include/FT8Demod.yaml#/FT8DemodReport" - RTTYDemodReport: - $ref: "http://swgserver:8081/api/swagger/include/RTTYDemod.yaml#/RTTYDemodReport" HeatMapReport: $ref: "http://swgserver:8081/api/swagger/include/HeatMap.yaml#/HeatMapReport" ILSDemodReport: @@ -81,6 +79,8 @@ ChannelReport: $ref: "http://swgserver:8081/api/swagger/include/RadiosondeDemod.yaml#/RadiosondeDemodReport" RemoteSourceReport: $ref: "http://swgserver:8081/api/swagger/include/RemoteSource.yaml#/RemoteSourceReport" + RTTYDemodReport: + $ref: "http://swgserver:8081/api/swagger/include/RTTYDemod.yaml#/RTTYDemodReport" RTTYModReport: $ref: "http://swgserver:8081/api/swagger/include/RTTYMod.yaml#/RTTYModReport" PacketDemodReport: @@ -89,6 +89,8 @@ ChannelReport: $ref: "http://swgserver:8081/api/swagger/include/PacketMod.yaml#/PacketModReport" PagerDemodReport: $ref: "http://swgserver:8081/api/swagger/include/PagerDemod.yaml#/PagerDemodReport" + PSK31ModReport: + $ref: "http://swgserver:8081/api/swagger/include/PSK31Mod.yaml#/PSK31ModReport" SigMFFileSinkReport: $ref: "http://swgserver:8081/api/swagger/include/SigMFFileSink.yaml#/SigMFFileSinkReport" SSBModReport: diff --git a/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml b/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml index a504187c98..42e566dfba 100644 --- a/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml +++ b/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml @@ -67,10 +67,6 @@ ChannelSettings: $ref: "http://swgserver:8081/api/swagger/include/FreqTracker.yaml#/FreqTrackerSettings" FT8DemodSettings: $ref: "http://swgserver:8081/api/swagger/include/FT8Demod.yaml#/FT8DemodSettings" - RTTYDemodSettings: - $ref: "http://swgserver:8081/api/swagger/include/RTTYDemod.yaml#/RTTYDemodSettings" - RTTYModSettings: - $ref: "http://swgserver:8081/api/swagger/include/RTTYMod.yaml#/RTTYModSettings" HeatMapSettings: $ref: "http://swgserver:8081/api/swagger/include/HeatMap.yaml#/HeatMapSettings" ILSDemodSettings: @@ -101,6 +97,8 @@ ChannelSettings: $ref: "http://swgserver:8081/api/swagger/include/PacketMod.yaml#/PacketModSettings" PagerDemodSettings: $ref: "http://swgserver:8081/api/swagger/include/PagerDemod.yaml#/PagerDemodSettings" + PSK31ModSettings: + $ref: "http://swgserver:8081/api/swagger/include/PSK31Mod.yaml#/PSK31ModSettings" RadioAstronomySettings: $ref: "http://swgserver:8081/api/swagger/include/RadioAstronomy.yaml#/RadioAstronomySettings" RadioClockSettings: @@ -113,6 +111,10 @@ ChannelSettings: $ref: "http://swgserver:8081/api/swagger/include/RemoteSource.yaml#/RemoteSourceSettings" RemoteTCPSinkSettings: $ref: "http://swgserver:8081/api/swagger/include/RemoteTCPSink.yaml#/RemoteTCPSinkSettings" + RTTYDemodSettings: + $ref: "http://swgserver:8081/api/swagger/include/RTTYDemod.yaml#/RTTYDemodSettings" + RTTYModSettings: + $ref: "http://swgserver:8081/api/swagger/include/RTTYMod.yaml#/RTTYModSettings" SigMFFileSinkSettings: $ref: "http://swgserver:8081/api/swagger/include/SigMFFileSink.yaml#/SigMFFileSinkSettings" SSBModSettings: diff --git a/swagger/sdrangel/api/swagger/include/PSK31Mod.yaml b/swagger/sdrangel/api/swagger/include/PSK31Mod.yaml new file mode 100644 index 0000000000..bc08b80cd9 --- /dev/null +++ b/swagger/sdrangel/api/swagger/include/PSK31Mod.yaml @@ -0,0 +1,99 @@ +PSK31ModSettings: + description: PSK31Mod + properties: + inputFrequencyOffset: + type: integer + format: int64 + rfBandwidth: + type: integer + gain: + type: number + format: float + channelMute: + type: integer + repeat: + type: integer + repeatCount: + type: integer + lpfTaps: + type: integer + rfNoise: + type: integer + description: > + Boolean + * 0 - off + * 1 - on + text: + type: string + description: Text to transmit + pulseShaping: + type: integer + description: > + Boolean + * 0 - off + * 1 - on + beta: + type: number + format: float + symbolSpan: + type: integer + prefixCRLF: + type: integer + postfixCRLF: + type: integer + udpEnabled: + description: "Whether to receive text to transmit on specified UDP port" + type: integer + udpAddress: + description: "UDP address to receive text to transmit via" + type: string + udpPort: + description: "UDP port to receive text to transmit via" + type: integer + rgbColor: + type: integer + title: + type: string + streamIndex: + description: MIMO channel. Not relevant when connected to SI (single Rx). + type: integer + useReverseAPI: + description: Synchronize with reverse API (1 for yes, 0 for no) + type: integer + reverseAPIAddress: + type: string + reverseAPIPort: + type: integer + reverseAPIDeviceIndex: + type: integer + reverseAPIChannelIndex: + type: integer + channelMarker: + $ref: "http://swgserver:8081/api/swagger/include/ChannelMarker.yaml#/ChannelMarker" + rollupState: + $ref: "http://swgserver:8081/api/swagger/include/RollupState.yaml#/RollupState" + +PSK31ModReport: + description: PSK31Mod + properties: + channelPowerDB: + description: power transmitted in channel (dB) + type: number + format: float + channelSampleRate: + type: integer + +PSK31ModActions: + description: PSK31Mod + properties: + tx: + type: integer + description: > + Transmit current text + * 0 - Do nothing + * 1 - Transmit + payload: + type: object + properties: + text: + type: string diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index c35209233e..50580a0f6c 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -3481,6 +3481,9 @@ "PacketModActions" : { "$ref" : "#/definitions/PacketModActions" }, + "PSK31ModActions" : { + "$ref" : "#/definitions/PSK31ModActions" + }, "RadioAstronomyActions" : { "$ref" : "#/definitions/RadioAstronomyActions" }, @@ -3734,9 +3737,6 @@ "FT8DemodReport" : { "$ref" : "#/definitions/FT8DemodReport" }, - "RTTYDemodReport" : { - "$ref" : "#/definitions/RTTYDemodReport" - }, "HeatMapReport" : { "$ref" : "#/definitions/HeatMapReport" }, @@ -3776,6 +3776,9 @@ "RemoteSourceReport" : { "$ref" : "#/definitions/RemoteSourceReport" }, + "RTTYDemodReport" : { + "$ref" : "#/definitions/RTTYDemodReport" + }, "RTTYModReport" : { "$ref" : "#/definitions/RTTYModReport" }, @@ -3788,6 +3791,9 @@ "PagerDemodReport" : { "$ref" : "#/definitions/PagerDemodReport" }, + "PSK31ModReport" : { + "$ref" : "#/definitions/PSK31ModReport" + }, "SigMFFileSinkReport" : { "$ref" : "#/definitions/SigMFFileSinkReport" }, @@ -3907,12 +3913,6 @@ "FT8DemodSettings" : { "$ref" : "#/definitions/FT8DemodSettings" }, - "RTTYDemodSettings" : { - "$ref" : "#/definitions/RTTYDemodSettings" - }, - "RTTYModSettings" : { - "$ref" : "#/definitions/RTTYModSettings" - }, "HeatMapSettings" : { "$ref" : "#/definitions/HeatMapSettings" }, @@ -3958,6 +3958,9 @@ "PagerDemodSettings" : { "$ref" : "#/definitions/PagerDemodSettings" }, + "PSK31ModSettings" : { + "$ref" : "#/definitions/PSK31ModSettings" + }, "RadioAstronomySettings" : { "$ref" : "#/definitions/RadioAstronomySettings" }, @@ -3976,6 +3979,12 @@ "RemoteTCPSinkSettings" : { "$ref" : "#/definitions/RemoteTCPSinkSettings" }, + "RTTYDemodSettings" : { + "$ref" : "#/definitions/RTTYDemodSettings" + }, + "RTTYModSettings" : { + "$ref" : "#/definitions/RTTYModSettings" + }, "SigMFFileSinkSettings" : { "$ref" : "#/definitions/SigMFFileSinkSettings" }, @@ -10522,6 +10531,135 @@ } }, "description" : "PER Tester settings" +}; + defs.PSK31ModActions = { + "properties" : { + "tx" : { + "type" : "integer", + "description" : "Transmit current text\n * 0 - Do nothing\n * 1 - Transmit\n" + }, + "payload" : { + "$ref" : "#/definitions/PSK31ModActions_payload" + } + }, + "description" : "PSK31Mod" +}; + defs.PSK31ModActions_payload = { + "properties" : { + "text" : { + "type" : "string" + } + } +}; + defs.PSK31ModReport = { + "properties" : { + "channelPowerDB" : { + "type" : "number", + "format" : "float", + "description" : "power transmitted in channel (dB)" + }, + "channelSampleRate" : { + "type" : "integer" + } + }, + "description" : "PSK31Mod" +}; + defs.PSK31ModSettings = { + "properties" : { + "inputFrequencyOffset" : { + "type" : "integer", + "format" : "int64" + }, + "rfBandwidth" : { + "type" : "integer" + }, + "gain" : { + "type" : "number", + "format" : "float" + }, + "channelMute" : { + "type" : "integer" + }, + "repeat" : { + "type" : "integer" + }, + "repeatCount" : { + "type" : "integer" + }, + "lpfTaps" : { + "type" : "integer" + }, + "rfNoise" : { + "type" : "integer", + "description" : "Boolean\n * 0 - off\n * 1 - on\n" + }, + "text" : { + "type" : "string", + "description" : "Text to transmit" + }, + "pulseShaping" : { + "type" : "integer", + "description" : "Boolean\n * 0 - off\n * 1 - on\n" + }, + "beta" : { + "type" : "number", + "format" : "float" + }, + "symbolSpan" : { + "type" : "integer" + }, + "prefixCRLF" : { + "type" : "integer" + }, + "postfixCRLF" : { + "type" : "integer" + }, + "udpEnabled" : { + "type" : "integer", + "description" : "Whether to receive text to transmit on specified UDP port" + }, + "udpAddress" : { + "type" : "string", + "description" : "UDP address to receive text to transmit via" + }, + "udpPort" : { + "type" : "integer", + "description" : "UDP port to receive text to transmit via" + }, + "rgbColor" : { + "type" : "integer" + }, + "title" : { + "type" : "string" + }, + "streamIndex" : { + "type" : "integer", + "description" : "MIMO channel. Not relevant when connected to SI (single Rx)." + }, + "useReverseAPI" : { + "type" : "integer", + "description" : "Synchronize with reverse API (1 for yes, 0 for no)" + }, + "reverseAPIAddress" : { + "type" : "string" + }, + "reverseAPIPort" : { + "type" : "integer" + }, + "reverseAPIDeviceIndex" : { + "type" : "integer" + }, + "reverseAPIChannelIndex" : { + "type" : "integer" + }, + "channelMarker" : { + "$ref" : "#/definitions/ChannelMarker" + }, + "rollupState" : { + "$ref" : "#/definitions/RollupState" + } + }, + "description" : "PSK31Mod" }; defs.PacketDemodReport = { "properties" : { @@ -11770,17 +11908,10 @@ "description" : "Transmit current text\n * 0 - Do nothing\n * 1 - Transmit\n" }, "payload" : { - "$ref" : "#/definitions/RTTYModActions_payload" + "$ref" : "#/definitions/PSK31ModActions_payload" } }, "description" : "RTTYMod" -}; - defs.RTTYModActions_payload = { - "properties" : { - "text" : { - "type" : "string" - } - } }; defs.RTTYModReport = { "properties" : { @@ -57994,7 +58125,7 @@

Status: 501 - Function not implemented

- Generated 2023-09-01T21:10:19.928+02:00 + Generated 2023-09-06T16:40:34.426+02:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelActions.cpp b/swagger/sdrangel/code/qt5/client/SWGChannelActions.cpp index 48bc150dc2..767398c252 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelActions.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGChannelActions.cpp @@ -48,6 +48,8 @@ SWGChannelActions::SWGChannelActions() { m_ieee_802_15_4_mod_actions_isSet = false; packet_mod_actions = nullptr; m_packet_mod_actions_isSet = false; + psk31_mod_actions = nullptr; + m_psk31_mod_actions_isSet = false; radio_astronomy_actions = nullptr; m_radio_astronomy_actions_isSet = false; rtty_mod_actions = nullptr; @@ -82,6 +84,8 @@ SWGChannelActions::init() { m_ieee_802_15_4_mod_actions_isSet = false; packet_mod_actions = new SWGPacketModActions(); m_packet_mod_actions_isSet = false; + psk31_mod_actions = new SWGPSK31ModActions(); + m_psk31_mod_actions_isSet = false; radio_astronomy_actions = new SWGRadioAstronomyActions(); m_radio_astronomy_actions_isSet = false; rtty_mod_actions = new SWGRTTYModActions(); @@ -116,6 +120,9 @@ SWGChannelActions::cleanup() { if(packet_mod_actions != nullptr) { delete packet_mod_actions; } + if(psk31_mod_actions != nullptr) { + delete psk31_mod_actions; + } if(radio_astronomy_actions != nullptr) { delete radio_astronomy_actions; } @@ -158,6 +165,8 @@ SWGChannelActions::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&packet_mod_actions, pJson["PacketModActions"], "SWGPacketModActions", "SWGPacketModActions"); + ::SWGSDRangel::setValue(&psk31_mod_actions, pJson["PSK31ModActions"], "SWGPSK31ModActions", "SWGPSK31ModActions"); + ::SWGSDRangel::setValue(&radio_astronomy_actions, pJson["RadioAstronomyActions"], "SWGRadioAstronomyActions", "SWGRadioAstronomyActions"); ::SWGSDRangel::setValue(&rtty_mod_actions, pJson["RTTYModActions"], "SWGRTTYModActions", "SWGRTTYModActions"); @@ -210,6 +219,9 @@ SWGChannelActions::asJsonObject() { if((packet_mod_actions != nullptr) && (packet_mod_actions->isSet())){ toJsonValue(QString("PacketModActions"), packet_mod_actions, obj, QString("SWGPacketModActions")); } + if((psk31_mod_actions != nullptr) && (psk31_mod_actions->isSet())){ + toJsonValue(QString("PSK31ModActions"), psk31_mod_actions, obj, QString("SWGPSK31ModActions")); + } if((radio_astronomy_actions != nullptr) && (radio_astronomy_actions->isSet())){ toJsonValue(QString("RadioAstronomyActions"), radio_astronomy_actions, obj, QString("SWGRadioAstronomyActions")); } @@ -323,6 +335,16 @@ SWGChannelActions::setPacketModActions(SWGPacketModActions* packet_mod_actions) this->m_packet_mod_actions_isSet = true; } +SWGPSK31ModActions* +SWGChannelActions::getPsk31ModActions() { + return psk31_mod_actions; +} +void +SWGChannelActions::setPsk31ModActions(SWGPSK31ModActions* psk31_mod_actions) { + this->psk31_mod_actions = psk31_mod_actions; + this->m_psk31_mod_actions_isSet = true; +} + SWGRadioAstronomyActions* SWGChannelActions::getRadioAstronomyActions() { return radio_astronomy_actions; @@ -388,6 +410,9 @@ SWGChannelActions::isSet(){ if(packet_mod_actions && packet_mod_actions->isSet()){ isObjectUpdated = true; break; } + if(psk31_mod_actions && psk31_mod_actions->isSet()){ + isObjectUpdated = true; break; + } if(radio_astronomy_actions && radio_astronomy_actions->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelActions.h b/swagger/sdrangel/code/qt5/client/SWGChannelActions.h index 48e4ff5f05..c93e066d57 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelActions.h +++ b/swagger/sdrangel/code/qt5/client/SWGChannelActions.h @@ -27,6 +27,7 @@ #include "SWGFileSinkActions.h" #include "SWGFileSourceActions.h" #include "SWGIEEE_802_15_4_ModActions.h" +#include "SWGPSK31ModActions.h" #include "SWGPacketModActions.h" #include "SWGRTTYModActions.h" #include "SWGRadioAstronomyActions.h" @@ -81,6 +82,9 @@ class SWG_API SWGChannelActions: public SWGObject { SWGPacketModActions* getPacketModActions(); void setPacketModActions(SWGPacketModActions* packet_mod_actions); + SWGPSK31ModActions* getPsk31ModActions(); + void setPsk31ModActions(SWGPSK31ModActions* psk31_mod_actions); + SWGRadioAstronomyActions* getRadioAstronomyActions(); void setRadioAstronomyActions(SWGRadioAstronomyActions* radio_astronomy_actions); @@ -124,6 +128,9 @@ class SWG_API SWGChannelActions: public SWGObject { SWGPacketModActions* packet_mod_actions; bool m_packet_mod_actions_isSet; + SWGPSK31ModActions* psk31_mod_actions; + bool m_psk31_mod_actions_isSet; + SWGRadioAstronomyActions* radio_astronomy_actions; bool m_radio_astronomy_actions_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelReport.cpp b/swagger/sdrangel/code/qt5/client/SWGChannelReport.cpp index f3fa2b538d..15761e3783 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelReport.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGChannelReport.cpp @@ -74,8 +74,6 @@ SWGChannelReport::SWGChannelReport() { m_freq_tracker_report_isSet = false; ft8_demod_report = nullptr; m_ft8_demod_report_isSet = false; - rtty_demod_report = nullptr; - m_rtty_demod_report_isSet = false; heat_map_report = nullptr; m_heat_map_report_isSet = false; ils_demod_report = nullptr; @@ -102,6 +100,8 @@ SWGChannelReport::SWGChannelReport() { m_radiosonde_demod_report_isSet = false; remote_source_report = nullptr; m_remote_source_report_isSet = false; + rtty_demod_report = nullptr; + m_rtty_demod_report_isSet = false; rtty_mod_report = nullptr; m_rtty_mod_report_isSet = false; packet_demod_report = nullptr; @@ -110,6 +110,8 @@ SWGChannelReport::SWGChannelReport() { m_packet_mod_report_isSet = false; pager_demod_report = nullptr; m_pager_demod_report_isSet = false; + psk31_mod_report = nullptr; + m_psk31_mod_report_isSet = false; sig_mf_file_sink_report = nullptr; m_sig_mf_file_sink_report_isSet = false; ssb_mod_report = nullptr; @@ -178,8 +180,6 @@ SWGChannelReport::init() { m_freq_tracker_report_isSet = false; ft8_demod_report = new SWGFT8DemodReport(); m_ft8_demod_report_isSet = false; - rtty_demod_report = new SWGRTTYDemodReport(); - m_rtty_demod_report_isSet = false; heat_map_report = new SWGHeatMapReport(); m_heat_map_report_isSet = false; ils_demod_report = new SWGILSDemodReport(); @@ -206,6 +206,8 @@ SWGChannelReport::init() { m_radiosonde_demod_report_isSet = false; remote_source_report = new SWGRemoteSourceReport(); m_remote_source_report_isSet = false; + rtty_demod_report = new SWGRTTYDemodReport(); + m_rtty_demod_report_isSet = false; rtty_mod_report = new SWGRTTYModReport(); m_rtty_mod_report_isSet = false; packet_demod_report = new SWGPacketDemodReport(); @@ -214,6 +216,8 @@ SWGChannelReport::init() { m_packet_mod_report_isSet = false; pager_demod_report = new SWGPagerDemodReport(); m_pager_demod_report_isSet = false; + psk31_mod_report = new SWGPSK31ModReport(); + m_psk31_mod_report_isSet = false; sig_mf_file_sink_report = new SWGSigMFFileSinkReport(); m_sig_mf_file_sink_report_isSet = false; ssb_mod_report = new SWGSSBModReport(); @@ -299,9 +303,6 @@ SWGChannelReport::cleanup() { if(ft8_demod_report != nullptr) { delete ft8_demod_report; } - if(rtty_demod_report != nullptr) { - delete rtty_demod_report; - } if(heat_map_report != nullptr) { delete heat_map_report; } @@ -341,6 +342,9 @@ SWGChannelReport::cleanup() { if(remote_source_report != nullptr) { delete remote_source_report; } + if(rtty_demod_report != nullptr) { + delete rtty_demod_report; + } if(rtty_mod_report != nullptr) { delete rtty_mod_report; } @@ -353,6 +357,9 @@ SWGChannelReport::cleanup() { if(pager_demod_report != nullptr) { delete pager_demod_report; } + if(psk31_mod_report != nullptr) { + delete psk31_mod_report; + } if(sig_mf_file_sink_report != nullptr) { delete sig_mf_file_sink_report; } @@ -433,8 +440,6 @@ SWGChannelReport::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&ft8_demod_report, pJson["FT8DemodReport"], "SWGFT8DemodReport", "SWGFT8DemodReport"); - ::SWGSDRangel::setValue(&rtty_demod_report, pJson["RTTYDemodReport"], "SWGRTTYDemodReport", "SWGRTTYDemodReport"); - ::SWGSDRangel::setValue(&heat_map_report, pJson["HeatMapReport"], "SWGHeatMapReport", "SWGHeatMapReport"); ::SWGSDRangel::setValue(&ils_demod_report, pJson["ILSDemodReport"], "SWGILSDemodReport", "SWGILSDemodReport"); @@ -461,6 +466,8 @@ SWGChannelReport::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&remote_source_report, pJson["RemoteSourceReport"], "SWGRemoteSourceReport", "SWGRemoteSourceReport"); + ::SWGSDRangel::setValue(&rtty_demod_report, pJson["RTTYDemodReport"], "SWGRTTYDemodReport", "SWGRTTYDemodReport"); + ::SWGSDRangel::setValue(&rtty_mod_report, pJson["RTTYModReport"], "SWGRTTYModReport", "SWGRTTYModReport"); ::SWGSDRangel::setValue(&packet_demod_report, pJson["PacketDemodReport"], "SWGPacketDemodReport", "SWGPacketDemodReport"); @@ -469,6 +476,8 @@ SWGChannelReport::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&pager_demod_report, pJson["PagerDemodReport"], "SWGPagerDemodReport", "SWGPagerDemodReport"); + ::SWGSDRangel::setValue(&psk31_mod_report, pJson["PSK31ModReport"], "SWGPSK31ModReport", "SWGPSK31ModReport"); + ::SWGSDRangel::setValue(&sig_mf_file_sink_report, pJson["SigMFFileSinkReport"], "SWGSigMFFileSinkReport", "SWGSigMFFileSinkReport"); ::SWGSDRangel::setValue(&ssb_mod_report, pJson["SSBModReport"], "SWGSSBModReport", "SWGSSBModReport"); @@ -568,9 +577,6 @@ SWGChannelReport::asJsonObject() { if((ft8_demod_report != nullptr) && (ft8_demod_report->isSet())){ toJsonValue(QString("FT8DemodReport"), ft8_demod_report, obj, QString("SWGFT8DemodReport")); } - if((rtty_demod_report != nullptr) && (rtty_demod_report->isSet())){ - toJsonValue(QString("RTTYDemodReport"), rtty_demod_report, obj, QString("SWGRTTYDemodReport")); - } if((heat_map_report != nullptr) && (heat_map_report->isSet())){ toJsonValue(QString("HeatMapReport"), heat_map_report, obj, QString("SWGHeatMapReport")); } @@ -610,6 +616,9 @@ SWGChannelReport::asJsonObject() { if((remote_source_report != nullptr) && (remote_source_report->isSet())){ toJsonValue(QString("RemoteSourceReport"), remote_source_report, obj, QString("SWGRemoteSourceReport")); } + if((rtty_demod_report != nullptr) && (rtty_demod_report->isSet())){ + toJsonValue(QString("RTTYDemodReport"), rtty_demod_report, obj, QString("SWGRTTYDemodReport")); + } if((rtty_mod_report != nullptr) && (rtty_mod_report->isSet())){ toJsonValue(QString("RTTYModReport"), rtty_mod_report, obj, QString("SWGRTTYModReport")); } @@ -622,6 +631,9 @@ SWGChannelReport::asJsonObject() { if((pager_demod_report != nullptr) && (pager_demod_report->isSet())){ toJsonValue(QString("PagerDemodReport"), pager_demod_report, obj, QString("SWGPagerDemodReport")); } + if((psk31_mod_report != nullptr) && (psk31_mod_report->isSet())){ + toJsonValue(QString("PSK31ModReport"), psk31_mod_report, obj, QString("SWGPSK31ModReport")); + } if((sig_mf_file_sink_report != nullptr) && (sig_mf_file_sink_report->isSet())){ toJsonValue(QString("SigMFFileSinkReport"), sig_mf_file_sink_report, obj, QString("SWGSigMFFileSinkReport")); } @@ -877,16 +889,6 @@ SWGChannelReport::setFt8DemodReport(SWGFT8DemodReport* ft8_demod_report) { this->m_ft8_demod_report_isSet = true; } -SWGRTTYDemodReport* -SWGChannelReport::getRttyDemodReport() { - return rtty_demod_report; -} -void -SWGChannelReport::setRttyDemodReport(SWGRTTYDemodReport* rtty_demod_report) { - this->rtty_demod_report = rtty_demod_report; - this->m_rtty_demod_report_isSet = true; -} - SWGHeatMapReport* SWGChannelReport::getHeatMapReport() { return heat_map_report; @@ -1017,6 +1019,16 @@ SWGChannelReport::setRemoteSourceReport(SWGRemoteSourceReport* remote_source_rep this->m_remote_source_report_isSet = true; } +SWGRTTYDemodReport* +SWGChannelReport::getRttyDemodReport() { + return rtty_demod_report; +} +void +SWGChannelReport::setRttyDemodReport(SWGRTTYDemodReport* rtty_demod_report) { + this->rtty_demod_report = rtty_demod_report; + this->m_rtty_demod_report_isSet = true; +} + SWGRTTYModReport* SWGChannelReport::getRttyModReport() { return rtty_mod_report; @@ -1057,6 +1069,16 @@ SWGChannelReport::setPagerDemodReport(SWGPagerDemodReport* pager_demod_report) { this->m_pager_demod_report_isSet = true; } +SWGPSK31ModReport* +SWGChannelReport::getPsk31ModReport() { + return psk31_mod_report; +} +void +SWGChannelReport::setPsk31ModReport(SWGPSK31ModReport* psk31_mod_report) { + this->psk31_mod_report = psk31_mod_report; + this->m_psk31_mod_report_isSet = true; +} + SWGSigMFFileSinkReport* SWGChannelReport::getSigMfFileSinkReport() { return sig_mf_file_sink_report; @@ -1201,9 +1223,6 @@ SWGChannelReport::isSet(){ if(ft8_demod_report && ft8_demod_report->isSet()){ isObjectUpdated = true; break; } - if(rtty_demod_report && rtty_demod_report->isSet()){ - isObjectUpdated = true; break; - } if(heat_map_report && heat_map_report->isSet()){ isObjectUpdated = true; break; } @@ -1243,6 +1262,9 @@ SWGChannelReport::isSet(){ if(remote_source_report && remote_source_report->isSet()){ isObjectUpdated = true; break; } + if(rtty_demod_report && rtty_demod_report->isSet()){ + isObjectUpdated = true; break; + } if(rtty_mod_report && rtty_mod_report->isSet()){ isObjectUpdated = true; break; } @@ -1255,6 +1277,9 @@ SWGChannelReport::isSet(){ if(pager_demod_report && pager_demod_report->isSet()){ isObjectUpdated = true; break; } + if(psk31_mod_report && psk31_mod_report->isSet()){ + isObjectUpdated = true; break; + } if(sig_mf_file_sink_report && sig_mf_file_sink_report->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelReport.h b/swagger/sdrangel/code/qt5/client/SWGChannelReport.h index 5e764550d2..7e16b278f7 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelReport.h +++ b/swagger/sdrangel/code/qt5/client/SWGChannelReport.h @@ -51,6 +51,7 @@ #include "SWGNFMModReport.h" #include "SWGNavtexDemodReport.h" #include "SWGNoiseFigureReport.h" +#include "SWGPSK31ModReport.h" #include "SWGPacketDemodReport.h" #include "SWGPacketModReport.h" #include "SWGPagerDemodReport.h" @@ -157,9 +158,6 @@ class SWG_API SWGChannelReport: public SWGObject { SWGFT8DemodReport* getFt8DemodReport(); void setFt8DemodReport(SWGFT8DemodReport* ft8_demod_report); - SWGRTTYDemodReport* getRttyDemodReport(); - void setRttyDemodReport(SWGRTTYDemodReport* rtty_demod_report); - SWGHeatMapReport* getHeatMapReport(); void setHeatMapReport(SWGHeatMapReport* heat_map_report); @@ -199,6 +197,9 @@ class SWG_API SWGChannelReport: public SWGObject { SWGRemoteSourceReport* getRemoteSourceReport(); void setRemoteSourceReport(SWGRemoteSourceReport* remote_source_report); + SWGRTTYDemodReport* getRttyDemodReport(); + void setRttyDemodReport(SWGRTTYDemodReport* rtty_demod_report); + SWGRTTYModReport* getRttyModReport(); void setRttyModReport(SWGRTTYModReport* rtty_mod_report); @@ -211,6 +212,9 @@ class SWG_API SWGChannelReport: public SWGObject { SWGPagerDemodReport* getPagerDemodReport(); void setPagerDemodReport(SWGPagerDemodReport* pager_demod_report); + SWGPSK31ModReport* getPsk31ModReport(); + void setPsk31ModReport(SWGPSK31ModReport* psk31_mod_report); + SWGSigMFFileSinkReport* getSigMfFileSinkReport(); void setSigMfFileSinkReport(SWGSigMFFileSinkReport* sig_mf_file_sink_report); @@ -305,9 +309,6 @@ class SWG_API SWGChannelReport: public SWGObject { SWGFT8DemodReport* ft8_demod_report; bool m_ft8_demod_report_isSet; - SWGRTTYDemodReport* rtty_demod_report; - bool m_rtty_demod_report_isSet; - SWGHeatMapReport* heat_map_report; bool m_heat_map_report_isSet; @@ -347,6 +348,9 @@ class SWG_API SWGChannelReport: public SWGObject { SWGRemoteSourceReport* remote_source_report; bool m_remote_source_report_isSet; + SWGRTTYDemodReport* rtty_demod_report; + bool m_rtty_demod_report_isSet; + SWGRTTYModReport* rtty_mod_report; bool m_rtty_mod_report_isSet; @@ -359,6 +363,9 @@ class SWG_API SWGChannelReport: public SWGObject { SWGPagerDemodReport* pager_demod_report; bool m_pager_demod_report_isSet; + SWGPSK31ModReport* psk31_mod_report; + bool m_psk31_mod_report_isSet; + SWGSigMFFileSinkReport* sig_mf_file_sink_report; bool m_sig_mf_file_sink_report_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp index e2ed3ae46d..d65f5fc3f2 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp @@ -86,10 +86,6 @@ SWGChannelSettings::SWGChannelSettings() { m_freq_tracker_settings_isSet = false; ft8_demod_settings = nullptr; m_ft8_demod_settings_isSet = false; - rtty_demod_settings = nullptr; - m_rtty_demod_settings_isSet = false; - rtty_mod_settings = nullptr; - m_rtty_mod_settings_isSet = false; heat_map_settings = nullptr; m_heat_map_settings_isSet = false; ils_demod_settings = nullptr; @@ -120,6 +116,8 @@ SWGChannelSettings::SWGChannelSettings() { m_packet_mod_settings_isSet = false; pager_demod_settings = nullptr; m_pager_demod_settings_isSet = false; + psk31_mod_settings = nullptr; + m_psk31_mod_settings_isSet = false; radio_astronomy_settings = nullptr; m_radio_astronomy_settings_isSet = false; radio_clock_settings = nullptr; @@ -132,6 +130,10 @@ SWGChannelSettings::SWGChannelSettings() { m_remote_source_settings_isSet = false; remote_tcp_sink_settings = nullptr; m_remote_tcp_sink_settings_isSet = false; + rtty_demod_settings = nullptr; + m_rtty_demod_settings_isSet = false; + rtty_mod_settings = nullptr; + m_rtty_mod_settings_isSet = false; sig_mf_file_sink_settings = nullptr; m_sig_mf_file_sink_settings_isSet = false; ssb_mod_settings = nullptr; @@ -214,10 +216,6 @@ SWGChannelSettings::init() { m_freq_tracker_settings_isSet = false; ft8_demod_settings = new SWGFT8DemodSettings(); m_ft8_demod_settings_isSet = false; - rtty_demod_settings = new SWGRTTYDemodSettings(); - m_rtty_demod_settings_isSet = false; - rtty_mod_settings = new SWGRTTYModSettings(); - m_rtty_mod_settings_isSet = false; heat_map_settings = new SWGHeatMapSettings(); m_heat_map_settings_isSet = false; ils_demod_settings = new SWGILSDemodSettings(); @@ -248,6 +246,8 @@ SWGChannelSettings::init() { m_packet_mod_settings_isSet = false; pager_demod_settings = new SWGPagerDemodSettings(); m_pager_demod_settings_isSet = false; + psk31_mod_settings = new SWGPSK31ModSettings(); + m_psk31_mod_settings_isSet = false; radio_astronomy_settings = new SWGRadioAstronomySettings(); m_radio_astronomy_settings_isSet = false; radio_clock_settings = new SWGRadioClockSettings(); @@ -260,6 +260,10 @@ SWGChannelSettings::init() { m_remote_source_settings_isSet = false; remote_tcp_sink_settings = new SWGRemoteTCPSinkSettings(); m_remote_tcp_sink_settings_isSet = false; + rtty_demod_settings = new SWGRTTYDemodSettings(); + m_rtty_demod_settings_isSet = false; + rtty_mod_settings = new SWGRTTYModSettings(); + m_rtty_mod_settings_isSet = false; sig_mf_file_sink_settings = new SWGSigMFFileSinkSettings(); m_sig_mf_file_sink_settings_isSet = false; ssb_mod_settings = new SWGSSBModSettings(); @@ -361,12 +365,6 @@ SWGChannelSettings::cleanup() { if(ft8_demod_settings != nullptr) { delete ft8_demod_settings; } - if(rtty_demod_settings != nullptr) { - delete rtty_demod_settings; - } - if(rtty_mod_settings != nullptr) { - delete rtty_mod_settings; - } if(heat_map_settings != nullptr) { delete heat_map_settings; } @@ -412,6 +410,9 @@ SWGChannelSettings::cleanup() { if(pager_demod_settings != nullptr) { delete pager_demod_settings; } + if(psk31_mod_settings != nullptr) { + delete psk31_mod_settings; + } if(radio_astronomy_settings != nullptr) { delete radio_astronomy_settings; } @@ -430,6 +431,12 @@ SWGChannelSettings::cleanup() { if(remote_tcp_sink_settings != nullptr) { delete remote_tcp_sink_settings; } + if(rtty_demod_settings != nullptr) { + delete rtty_demod_settings; + } + if(rtty_mod_settings != nullptr) { + delete rtty_mod_settings; + } if(sig_mf_file_sink_settings != nullptr) { delete sig_mf_file_sink_settings; } @@ -525,10 +532,6 @@ SWGChannelSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&ft8_demod_settings, pJson["FT8DemodSettings"], "SWGFT8DemodSettings", "SWGFT8DemodSettings"); - ::SWGSDRangel::setValue(&rtty_demod_settings, pJson["RTTYDemodSettings"], "SWGRTTYDemodSettings", "SWGRTTYDemodSettings"); - - ::SWGSDRangel::setValue(&rtty_mod_settings, pJson["RTTYModSettings"], "SWGRTTYModSettings", "SWGRTTYModSettings"); - ::SWGSDRangel::setValue(&heat_map_settings, pJson["HeatMapSettings"], "SWGHeatMapSettings", "SWGHeatMapSettings"); ::SWGSDRangel::setValue(&ils_demod_settings, pJson["ILSDemodSettings"], "SWGILSDemodSettings", "SWGILSDemodSettings"); @@ -559,6 +562,8 @@ SWGChannelSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&pager_demod_settings, pJson["PagerDemodSettings"], "SWGPagerDemodSettings", "SWGPagerDemodSettings"); + ::SWGSDRangel::setValue(&psk31_mod_settings, pJson["PSK31ModSettings"], "SWGPSK31ModSettings", "SWGPSK31ModSettings"); + ::SWGSDRangel::setValue(&radio_astronomy_settings, pJson["RadioAstronomySettings"], "SWGRadioAstronomySettings", "SWGRadioAstronomySettings"); ::SWGSDRangel::setValue(&radio_clock_settings, pJson["RadioClockSettings"], "SWGRadioClockSettings", "SWGRadioClockSettings"); @@ -571,6 +576,10 @@ SWGChannelSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&remote_tcp_sink_settings, pJson["RemoteTCPSinkSettings"], "SWGRemoteTCPSinkSettings", "SWGRemoteTCPSinkSettings"); + ::SWGSDRangel::setValue(&rtty_demod_settings, pJson["RTTYDemodSettings"], "SWGRTTYDemodSettings", "SWGRTTYDemodSettings"); + + ::SWGSDRangel::setValue(&rtty_mod_settings, pJson["RTTYModSettings"], "SWGRTTYModSettings", "SWGRTTYModSettings"); + ::SWGSDRangel::setValue(&sig_mf_file_sink_settings, pJson["SigMFFileSinkSettings"], "SWGSigMFFileSinkSettings", "SWGSigMFFileSinkSettings"); ::SWGSDRangel::setValue(&ssb_mod_settings, pJson["SSBModSettings"], "SWGSSBModSettings", "SWGSSBModSettings"); @@ -690,12 +699,6 @@ SWGChannelSettings::asJsonObject() { if((ft8_demod_settings != nullptr) && (ft8_demod_settings->isSet())){ toJsonValue(QString("FT8DemodSettings"), ft8_demod_settings, obj, QString("SWGFT8DemodSettings")); } - if((rtty_demod_settings != nullptr) && (rtty_demod_settings->isSet())){ - toJsonValue(QString("RTTYDemodSettings"), rtty_demod_settings, obj, QString("SWGRTTYDemodSettings")); - } - if((rtty_mod_settings != nullptr) && (rtty_mod_settings->isSet())){ - toJsonValue(QString("RTTYModSettings"), rtty_mod_settings, obj, QString("SWGRTTYModSettings")); - } if((heat_map_settings != nullptr) && (heat_map_settings->isSet())){ toJsonValue(QString("HeatMapSettings"), heat_map_settings, obj, QString("SWGHeatMapSettings")); } @@ -741,6 +744,9 @@ SWGChannelSettings::asJsonObject() { if((pager_demod_settings != nullptr) && (pager_demod_settings->isSet())){ toJsonValue(QString("PagerDemodSettings"), pager_demod_settings, obj, QString("SWGPagerDemodSettings")); } + if((psk31_mod_settings != nullptr) && (psk31_mod_settings->isSet())){ + toJsonValue(QString("PSK31ModSettings"), psk31_mod_settings, obj, QString("SWGPSK31ModSettings")); + } if((radio_astronomy_settings != nullptr) && (radio_astronomy_settings->isSet())){ toJsonValue(QString("RadioAstronomySettings"), radio_astronomy_settings, obj, QString("SWGRadioAstronomySettings")); } @@ -759,6 +765,12 @@ SWGChannelSettings::asJsonObject() { if((remote_tcp_sink_settings != nullptr) && (remote_tcp_sink_settings->isSet())){ toJsonValue(QString("RemoteTCPSinkSettings"), remote_tcp_sink_settings, obj, QString("SWGRemoteTCPSinkSettings")); } + if((rtty_demod_settings != nullptr) && (rtty_demod_settings->isSet())){ + toJsonValue(QString("RTTYDemodSettings"), rtty_demod_settings, obj, QString("SWGRTTYDemodSettings")); + } + if((rtty_mod_settings != nullptr) && (rtty_mod_settings->isSet())){ + toJsonValue(QString("RTTYModSettings"), rtty_mod_settings, obj, QString("SWGRTTYModSettings")); + } if((sig_mf_file_sink_settings != nullptr) && (sig_mf_file_sink_settings->isSet())){ toJsonValue(QString("SigMFFileSinkSettings"), sig_mf_file_sink_settings, obj, QString("SWGSigMFFileSinkSettings")); } @@ -1077,26 +1089,6 @@ SWGChannelSettings::setFt8DemodSettings(SWGFT8DemodSettings* ft8_demod_settings) this->m_ft8_demod_settings_isSet = true; } -SWGRTTYDemodSettings* -SWGChannelSettings::getRttyDemodSettings() { - return rtty_demod_settings; -} -void -SWGChannelSettings::setRttyDemodSettings(SWGRTTYDemodSettings* rtty_demod_settings) { - this->rtty_demod_settings = rtty_demod_settings; - this->m_rtty_demod_settings_isSet = true; -} - -SWGRTTYModSettings* -SWGChannelSettings::getRttyModSettings() { - return rtty_mod_settings; -} -void -SWGChannelSettings::setRttyModSettings(SWGRTTYModSettings* rtty_mod_settings) { - this->rtty_mod_settings = rtty_mod_settings; - this->m_rtty_mod_settings_isSet = true; -} - SWGHeatMapSettings* SWGChannelSettings::getHeatMapSettings() { return heat_map_settings; @@ -1247,6 +1239,16 @@ SWGChannelSettings::setPagerDemodSettings(SWGPagerDemodSettings* pager_demod_set this->m_pager_demod_settings_isSet = true; } +SWGPSK31ModSettings* +SWGChannelSettings::getPsk31ModSettings() { + return psk31_mod_settings; +} +void +SWGChannelSettings::setPsk31ModSettings(SWGPSK31ModSettings* psk31_mod_settings) { + this->psk31_mod_settings = psk31_mod_settings; + this->m_psk31_mod_settings_isSet = true; +} + SWGRadioAstronomySettings* SWGChannelSettings::getRadioAstronomySettings() { return radio_astronomy_settings; @@ -1307,6 +1309,26 @@ SWGChannelSettings::setRemoteTcpSinkSettings(SWGRemoteTCPSinkSettings* remote_tc this->m_remote_tcp_sink_settings_isSet = true; } +SWGRTTYDemodSettings* +SWGChannelSettings::getRttyDemodSettings() { + return rtty_demod_settings; +} +void +SWGChannelSettings::setRttyDemodSettings(SWGRTTYDemodSettings* rtty_demod_settings) { + this->rtty_demod_settings = rtty_demod_settings; + this->m_rtty_demod_settings_isSet = true; +} + +SWGRTTYModSettings* +SWGChannelSettings::getRttyModSettings() { + return rtty_mod_settings; +} +void +SWGChannelSettings::setRttyModSettings(SWGRTTYModSettings* rtty_mod_settings) { + this->rtty_mod_settings = rtty_mod_settings; + this->m_rtty_mod_settings_isSet = true; +} + SWGSigMFFileSinkSettings* SWGChannelSettings::getSigMfFileSinkSettings() { return sig_mf_file_sink_settings; @@ -1479,12 +1501,6 @@ SWGChannelSettings::isSet(){ if(ft8_demod_settings && ft8_demod_settings->isSet()){ isObjectUpdated = true; break; } - if(rtty_demod_settings && rtty_demod_settings->isSet()){ - isObjectUpdated = true; break; - } - if(rtty_mod_settings && rtty_mod_settings->isSet()){ - isObjectUpdated = true; break; - } if(heat_map_settings && heat_map_settings->isSet()){ isObjectUpdated = true; break; } @@ -1530,6 +1546,9 @@ SWGChannelSettings::isSet(){ if(pager_demod_settings && pager_demod_settings->isSet()){ isObjectUpdated = true; break; } + if(psk31_mod_settings && psk31_mod_settings->isSet()){ + isObjectUpdated = true; break; + } if(radio_astronomy_settings && radio_astronomy_settings->isSet()){ isObjectUpdated = true; break; } @@ -1548,6 +1567,12 @@ SWGChannelSettings::isSet(){ if(remote_tcp_sink_settings && remote_tcp_sink_settings->isSet()){ isObjectUpdated = true; break; } + if(rtty_demod_settings && rtty_demod_settings->isSet()){ + isObjectUpdated = true; break; + } + if(rtty_mod_settings && rtty_mod_settings->isSet()){ + isObjectUpdated = true; break; + } if(sig_mf_file_sink_settings && sig_mf_file_sink_settings->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h index 7301be1b8d..9f652b0dd1 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h @@ -59,6 +59,7 @@ #include "SWGNFMModSettings.h" #include "SWGNavtexDemodSettings.h" #include "SWGNoiseFigureSettings.h" +#include "SWGPSK31ModSettings.h" #include "SWGPacketDemodSettings.h" #include "SWGPacketModSettings.h" #include "SWGPagerDemodSettings.h" @@ -185,12 +186,6 @@ class SWG_API SWGChannelSettings: public SWGObject { SWGFT8DemodSettings* getFt8DemodSettings(); void setFt8DemodSettings(SWGFT8DemodSettings* ft8_demod_settings); - SWGRTTYDemodSettings* getRttyDemodSettings(); - void setRttyDemodSettings(SWGRTTYDemodSettings* rtty_demod_settings); - - SWGRTTYModSettings* getRttyModSettings(); - void setRttyModSettings(SWGRTTYModSettings* rtty_mod_settings); - SWGHeatMapSettings* getHeatMapSettings(); void setHeatMapSettings(SWGHeatMapSettings* heat_map_settings); @@ -236,6 +231,9 @@ class SWG_API SWGChannelSettings: public SWGObject { SWGPagerDemodSettings* getPagerDemodSettings(); void setPagerDemodSettings(SWGPagerDemodSettings* pager_demod_settings); + SWGPSK31ModSettings* getPsk31ModSettings(); + void setPsk31ModSettings(SWGPSK31ModSettings* psk31_mod_settings); + SWGRadioAstronomySettings* getRadioAstronomySettings(); void setRadioAstronomySettings(SWGRadioAstronomySettings* radio_astronomy_settings); @@ -254,6 +252,12 @@ class SWG_API SWGChannelSettings: public SWGObject { SWGRemoteTCPSinkSettings* getRemoteTcpSinkSettings(); void setRemoteTcpSinkSettings(SWGRemoteTCPSinkSettings* remote_tcp_sink_settings); + SWGRTTYDemodSettings* getRttyDemodSettings(); + void setRttyDemodSettings(SWGRTTYDemodSettings* rtty_demod_settings); + + SWGRTTYModSettings* getRttyModSettings(); + void setRttyModSettings(SWGRTTYModSettings* rtty_mod_settings); + SWGSigMFFileSinkSettings* getSigMfFileSinkSettings(); void setSigMfFileSinkSettings(SWGSigMFFileSinkSettings* sig_mf_file_sink_settings); @@ -369,12 +373,6 @@ class SWG_API SWGChannelSettings: public SWGObject { SWGFT8DemodSettings* ft8_demod_settings; bool m_ft8_demod_settings_isSet; - SWGRTTYDemodSettings* rtty_demod_settings; - bool m_rtty_demod_settings_isSet; - - SWGRTTYModSettings* rtty_mod_settings; - bool m_rtty_mod_settings_isSet; - SWGHeatMapSettings* heat_map_settings; bool m_heat_map_settings_isSet; @@ -420,6 +418,9 @@ class SWG_API SWGChannelSettings: public SWGObject { SWGPagerDemodSettings* pager_demod_settings; bool m_pager_demod_settings_isSet; + SWGPSK31ModSettings* psk31_mod_settings; + bool m_psk31_mod_settings_isSet; + SWGRadioAstronomySettings* radio_astronomy_settings; bool m_radio_astronomy_settings_isSet; @@ -438,6 +439,12 @@ class SWG_API SWGChannelSettings: public SWGObject { SWGRemoteTCPSinkSettings* remote_tcp_sink_settings; bool m_remote_tcp_sink_settings_isSet; + SWGRTTYDemodSettings* rtty_demod_settings; + bool m_rtty_demod_settings_isSet; + + SWGRTTYModSettings* rtty_mod_settings; + bool m_rtty_mod_settings_isSet; + SWGSigMFFileSinkSettings* sig_mf_file_sink_settings; bool m_sig_mf_file_sink_settings_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h index a446bc49c0..909a3865e4 100644 --- a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h +++ b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h @@ -222,6 +222,10 @@ #include "SWGPERTesterActions_aos.h" #include "SWGPERTesterReport.h" #include "SWGPERTesterSettings.h" +#include "SWGPSK31ModActions.h" +#include "SWGPSK31ModActions_payload.h" +#include "SWGPSK31ModReport.h" +#include "SWGPSK31ModSettings.h" #include "SWGPacketDemodReport.h" #include "SWGPacketDemodSettings.h" #include "SWGPacketModActions.h" @@ -252,7 +256,6 @@ #include "SWGRTTYDemodReport.h" #include "SWGRTTYDemodSettings.h" #include "SWGRTTYModActions.h" -#include "SWGRTTYModActions_payload.h" #include "SWGRTTYModReport.h" #include "SWGRTTYModSettings.h" #include "SWGRadioAstronomyActions.h" @@ -1404,6 +1407,26 @@ namespace SWGSDRangel { obj->init(); return obj; } + if(QString("SWGPSK31ModActions").compare(type) == 0) { + SWGPSK31ModActions *obj = new SWGPSK31ModActions(); + obj->init(); + return obj; + } + if(QString("SWGPSK31ModActions_payload").compare(type) == 0) { + SWGPSK31ModActions_payload *obj = new SWGPSK31ModActions_payload(); + obj->init(); + return obj; + } + if(QString("SWGPSK31ModReport").compare(type) == 0) { + SWGPSK31ModReport *obj = new SWGPSK31ModReport(); + obj->init(); + return obj; + } + if(QString("SWGPSK31ModSettings").compare(type) == 0) { + SWGPSK31ModSettings *obj = new SWGPSK31ModSettings(); + obj->init(); + return obj; + } if(QString("SWGPacketDemodReport").compare(type) == 0) { SWGPacketDemodReport *obj = new SWGPacketDemodReport(); obj->init(); @@ -1554,11 +1577,6 @@ namespace SWGSDRangel { obj->init(); return obj; } - if(QString("SWGRTTYModActions_payload").compare(type) == 0) { - SWGRTTYModActions_payload *obj = new SWGRTTYModActions_payload(); - obj->init(); - return obj; - } if(QString("SWGRTTYModReport").compare(type) == 0) { SWGRTTYModReport *obj = new SWGRTTYModReport(); obj->init(); diff --git a/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions.cpp b/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions.cpp new file mode 100644 index 0000000000..d76f95868e --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions.cpp @@ -0,0 +1,133 @@ +/** + * 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: 7.0.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 "SWGPSK31ModActions.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGPSK31ModActions::SWGPSK31ModActions(QString* json) { + init(); + this->fromJson(*json); +} + +SWGPSK31ModActions::SWGPSK31ModActions() { + tx = 0; + m_tx_isSet = false; + payload = nullptr; + m_payload_isSet = false; +} + +SWGPSK31ModActions::~SWGPSK31ModActions() { + this->cleanup(); +} + +void +SWGPSK31ModActions::init() { + tx = 0; + m_tx_isSet = false; + payload = new SWGPSK31ModActions_payload(); + m_payload_isSet = false; +} + +void +SWGPSK31ModActions::cleanup() { + + if(payload != nullptr) { + delete payload; + } +} + +SWGPSK31ModActions* +SWGPSK31ModActions::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGPSK31ModActions::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&tx, pJson["tx"], "qint32", ""); + + ::SWGSDRangel::setValue(&payload, pJson["payload"], "SWGPSK31ModActions_payload", "SWGPSK31ModActions_payload"); + +} + +QString +SWGPSK31ModActions::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGPSK31ModActions::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_tx_isSet){ + obj->insert("tx", QJsonValue(tx)); + } + if((payload != nullptr) && (payload->isSet())){ + toJsonValue(QString("payload"), payload, obj, QString("SWGPSK31ModActions_payload")); + } + + return obj; +} + +qint32 +SWGPSK31ModActions::getTx() { + return tx; +} +void +SWGPSK31ModActions::setTx(qint32 tx) { + this->tx = tx; + this->m_tx_isSet = true; +} + +SWGPSK31ModActions_payload* +SWGPSK31ModActions::getPayload() { + return payload; +} +void +SWGPSK31ModActions::setPayload(SWGPSK31ModActions_payload* payload) { + this->payload = payload; + this->m_payload_isSet = true; +} + + +bool +SWGPSK31ModActions::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_tx_isSet){ + isObjectUpdated = true; break; + } + if(payload && payload->isSet()){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions.h b/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions.h new file mode 100644 index 0000000000..63caf6b6b1 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions.h @@ -0,0 +1,65 @@ +/** + * 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: 7.0.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. + */ + +/* + * SWGPSK31ModActions.h + * + * PSK31Mod + */ + +#ifndef SWGPSK31ModActions_H_ +#define SWGPSK31ModActions_H_ + +#include + + +#include "SWGPSK31ModActions_payload.h" + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGPSK31ModActions: public SWGObject { +public: + SWGPSK31ModActions(); + SWGPSK31ModActions(QString* json); + virtual ~SWGPSK31ModActions(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGPSK31ModActions* fromJson(QString &jsonString) override; + + qint32 getTx(); + void setTx(qint32 tx); + + SWGPSK31ModActions_payload* getPayload(); + void setPayload(SWGPSK31ModActions_payload* payload); + + + virtual bool isSet() override; + +private: + qint32 tx; + bool m_tx_isSet; + + SWGPSK31ModActions_payload* payload; + bool m_payload_isSet; + +}; + +} + +#endif /* SWGPSK31ModActions_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions_payload.cpp b/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions_payload.cpp new file mode 100644 index 0000000000..0a7f9ed8a3 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions_payload.cpp @@ -0,0 +1,110 @@ +/** + * 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: 7.0.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 "SWGPSK31ModActions_payload.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGPSK31ModActions_payload::SWGPSK31ModActions_payload(QString* json) { + init(); + this->fromJson(*json); +} + +SWGPSK31ModActions_payload::SWGPSK31ModActions_payload() { + text = nullptr; + m_text_isSet = false; +} + +SWGPSK31ModActions_payload::~SWGPSK31ModActions_payload() { + this->cleanup(); +} + +void +SWGPSK31ModActions_payload::init() { + text = new QString(""); + m_text_isSet = false; +} + +void +SWGPSK31ModActions_payload::cleanup() { + if(text != nullptr) { + delete text; + } +} + +SWGPSK31ModActions_payload* +SWGPSK31ModActions_payload::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGPSK31ModActions_payload::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&text, pJson["text"], "QString", "QString"); + +} + +QString +SWGPSK31ModActions_payload::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGPSK31ModActions_payload::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(text != nullptr && *text != QString("")){ + toJsonValue(QString("text"), text, obj, QString("QString")); + } + + return obj; +} + +QString* +SWGPSK31ModActions_payload::getText() { + return text; +} +void +SWGPSK31ModActions_payload::setText(QString* text) { + this->text = text; + this->m_text_isSet = true; +} + + +bool +SWGPSK31ModActions_payload::isSet(){ + bool isObjectUpdated = false; + do{ + if(text && *text != QString("")){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions_payload.h b/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions_payload.h new file mode 100644 index 0000000000..b31b67605e --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPSK31ModActions_payload.h @@ -0,0 +1,59 @@ +/** + * 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: 7.0.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. + */ + +/* + * SWGPSK31ModActions_payload.h + * + * + */ + +#ifndef SWGPSK31ModActions_payload_H_ +#define SWGPSK31ModActions_payload_H_ + +#include + + +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGPSK31ModActions_payload: public SWGObject { +public: + SWGPSK31ModActions_payload(); + SWGPSK31ModActions_payload(QString* json); + virtual ~SWGPSK31ModActions_payload(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGPSK31ModActions_payload* fromJson(QString &jsonString) override; + + QString* getText(); + void setText(QString* text); + + + virtual bool isSet() override; + +private: + QString* text; + bool m_text_isSet; + +}; + +} + +#endif /* SWGPSK31ModActions_payload_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGPSK31ModReport.cpp b/swagger/sdrangel/code/qt5/client/SWGPSK31ModReport.cpp new file mode 100644 index 0000000000..8d32d7e88b --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPSK31ModReport.cpp @@ -0,0 +1,131 @@ +/** + * 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: 7.0.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 "SWGPSK31ModReport.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGPSK31ModReport::SWGPSK31ModReport(QString* json) { + init(); + this->fromJson(*json); +} + +SWGPSK31ModReport::SWGPSK31ModReport() { + channel_power_db = 0.0f; + m_channel_power_db_isSet = false; + channel_sample_rate = 0; + m_channel_sample_rate_isSet = false; +} + +SWGPSK31ModReport::~SWGPSK31ModReport() { + this->cleanup(); +} + +void +SWGPSK31ModReport::init() { + channel_power_db = 0.0f; + m_channel_power_db_isSet = false; + channel_sample_rate = 0; + m_channel_sample_rate_isSet = false; +} + +void +SWGPSK31ModReport::cleanup() { + + +} + +SWGPSK31ModReport* +SWGPSK31ModReport::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGPSK31ModReport::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&channel_power_db, pJson["channelPowerDB"], "float", ""); + + ::SWGSDRangel::setValue(&channel_sample_rate, pJson["channelSampleRate"], "qint32", ""); + +} + +QString +SWGPSK31ModReport::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGPSK31ModReport::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_channel_power_db_isSet){ + obj->insert("channelPowerDB", QJsonValue(channel_power_db)); + } + if(m_channel_sample_rate_isSet){ + obj->insert("channelSampleRate", QJsonValue(channel_sample_rate)); + } + + return obj; +} + +float +SWGPSK31ModReport::getChannelPowerDb() { + return channel_power_db; +} +void +SWGPSK31ModReport::setChannelPowerDb(float channel_power_db) { + this->channel_power_db = channel_power_db; + this->m_channel_power_db_isSet = true; +} + +qint32 +SWGPSK31ModReport::getChannelSampleRate() { + return channel_sample_rate; +} +void +SWGPSK31ModReport::setChannelSampleRate(qint32 channel_sample_rate) { + this->channel_sample_rate = channel_sample_rate; + this->m_channel_sample_rate_isSet = true; +} + + +bool +SWGPSK31ModReport::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_channel_power_db_isSet){ + isObjectUpdated = true; break; + } + if(m_channel_sample_rate_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGPSK31ModReport.h b/swagger/sdrangel/code/qt5/client/SWGPSK31ModReport.h new file mode 100644 index 0000000000..24f5f1a259 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPSK31ModReport.h @@ -0,0 +1,64 @@ +/** + * 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: 7.0.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. + */ + +/* + * SWGPSK31ModReport.h + * + * PSK31Mod + */ + +#ifndef SWGPSK31ModReport_H_ +#define SWGPSK31ModReport_H_ + +#include + + + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGPSK31ModReport: public SWGObject { +public: + SWGPSK31ModReport(); + SWGPSK31ModReport(QString* json); + virtual ~SWGPSK31ModReport(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGPSK31ModReport* fromJson(QString &jsonString) override; + + float getChannelPowerDb(); + void setChannelPowerDb(float channel_power_db); + + qint32 getChannelSampleRate(); + void setChannelSampleRate(qint32 channel_sample_rate); + + + virtual bool isSet() override; + +private: + float channel_power_db; + bool m_channel_power_db_isSet; + + qint32 channel_sample_rate; + bool m_channel_sample_rate_isSet; + +}; + +} + +#endif /* SWGPSK31ModReport_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGPSK31ModSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGPSK31ModSettings.cpp new file mode 100644 index 0000000000..c2f814d76b --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPSK31ModSettings.cpp @@ -0,0 +1,718 @@ +/** + * 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: 7.0.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 "SWGPSK31ModSettings.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGPSK31ModSettings::SWGPSK31ModSettings(QString* json) { + init(); + this->fromJson(*json); +} + +SWGPSK31ModSettings::SWGPSK31ModSettings() { + input_frequency_offset = 0L; + m_input_frequency_offset_isSet = false; + rf_bandwidth = 0; + m_rf_bandwidth_isSet = false; + gain = 0.0f; + m_gain_isSet = false; + channel_mute = 0; + m_channel_mute_isSet = false; + repeat = 0; + m_repeat_isSet = false; + repeat_count = 0; + m_repeat_count_isSet = false; + lpf_taps = 0; + m_lpf_taps_isSet = false; + rf_noise = 0; + m_rf_noise_isSet = false; + text = nullptr; + m_text_isSet = false; + pulse_shaping = 0; + m_pulse_shaping_isSet = false; + beta = 0.0f; + m_beta_isSet = false; + symbol_span = 0; + m_symbol_span_isSet = false; + prefix_crlf = 0; + m_prefix_crlf_isSet = false; + postfix_crlf = 0; + m_postfix_crlf_isSet = false; + udp_enabled = 0; + m_udp_enabled_isSet = false; + udp_address = nullptr; + m_udp_address_isSet = false; + udp_port = 0; + m_udp_port_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + title = nullptr; + m_title_isSet = false; + stream_index = 0; + m_stream_index_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; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; + channel_marker = nullptr; + m_channel_marker_isSet = false; + rollup_state = nullptr; + m_rollup_state_isSet = false; +} + +SWGPSK31ModSettings::~SWGPSK31ModSettings() { + this->cleanup(); +} + +void +SWGPSK31ModSettings::init() { + input_frequency_offset = 0L; + m_input_frequency_offset_isSet = false; + rf_bandwidth = 0; + m_rf_bandwidth_isSet = false; + gain = 0.0f; + m_gain_isSet = false; + channel_mute = 0; + m_channel_mute_isSet = false; + repeat = 0; + m_repeat_isSet = false; + repeat_count = 0; + m_repeat_count_isSet = false; + lpf_taps = 0; + m_lpf_taps_isSet = false; + rf_noise = 0; + m_rf_noise_isSet = false; + text = new QString(""); + m_text_isSet = false; + pulse_shaping = 0; + m_pulse_shaping_isSet = false; + beta = 0.0f; + m_beta_isSet = false; + symbol_span = 0; + m_symbol_span_isSet = false; + prefix_crlf = 0; + m_prefix_crlf_isSet = false; + postfix_crlf = 0; + m_postfix_crlf_isSet = false; + udp_enabled = 0; + m_udp_enabled_isSet = false; + udp_address = new QString(""); + m_udp_address_isSet = false; + udp_port = 0; + m_udp_port_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + title = new QString(""); + m_title_isSet = false; + stream_index = 0; + m_stream_index_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; + reverse_api_channel_index = 0; + m_reverse_api_channel_index_isSet = false; + channel_marker = new SWGChannelMarker(); + m_channel_marker_isSet = false; + rollup_state = new SWGRollupState(); + m_rollup_state_isSet = false; +} + +void +SWGPSK31ModSettings::cleanup() { + + + + + + + + + if(text != nullptr) { + delete text; + } + + + + + + + if(udp_address != nullptr) { + delete udp_address; + } + + + if(title != nullptr) { + delete title; + } + + + if(reverse_api_address != nullptr) { + delete reverse_api_address; + } + + + + if(channel_marker != nullptr) { + delete channel_marker; + } + if(rollup_state != nullptr) { + delete rollup_state; + } +} + +SWGPSK31ModSettings* +SWGPSK31ModSettings::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGPSK31ModSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", ""); + + ::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "qint32", ""); + + ::SWGSDRangel::setValue(&gain, pJson["gain"], "float", ""); + + ::SWGSDRangel::setValue(&channel_mute, pJson["channelMute"], "qint32", ""); + + ::SWGSDRangel::setValue(&repeat, pJson["repeat"], "qint32", ""); + + ::SWGSDRangel::setValue(&repeat_count, pJson["repeatCount"], "qint32", ""); + + ::SWGSDRangel::setValue(&lpf_taps, pJson["lpfTaps"], "qint32", ""); + + ::SWGSDRangel::setValue(&rf_noise, pJson["rfNoise"], "qint32", ""); + + ::SWGSDRangel::setValue(&text, pJson["text"], "QString", "QString"); + + ::SWGSDRangel::setValue(&pulse_shaping, pJson["pulseShaping"], "qint32", ""); + + ::SWGSDRangel::setValue(&beta, pJson["beta"], "float", ""); + + ::SWGSDRangel::setValue(&symbol_span, pJson["symbolSpan"], "qint32", ""); + + ::SWGSDRangel::setValue(&prefix_crlf, pJson["prefixCRLF"], "qint32", ""); + + ::SWGSDRangel::setValue(&postfix_crlf, pJson["postfixCRLF"], "qint32", ""); + + ::SWGSDRangel::setValue(&udp_enabled, pJson["udpEnabled"], "qint32", ""); + + ::SWGSDRangel::setValue(&udp_address, pJson["udpAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&udp_port, pJson["udpPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); + + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + + ::SWGSDRangel::setValue(&stream_index, pJson["streamIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&use_reverse_api, pJson["useReverseAPI"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_address, pJson["reverseAPIAddress"], "QString", "QString"); + + ::SWGSDRangel::setValue(&reverse_api_port, pJson["reverseAPIPort"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_device_index, pJson["reverseAPIDeviceIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&reverse_api_channel_index, pJson["reverseAPIChannelIndex"], "qint32", ""); + + ::SWGSDRangel::setValue(&channel_marker, pJson["channelMarker"], "SWGChannelMarker", "SWGChannelMarker"); + + ::SWGSDRangel::setValue(&rollup_state, pJson["rollupState"], "SWGRollupState", "SWGRollupState"); + +} + +QString +SWGPSK31ModSettings::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGPSK31ModSettings::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_input_frequency_offset_isSet){ + obj->insert("inputFrequencyOffset", QJsonValue(input_frequency_offset)); + } + if(m_rf_bandwidth_isSet){ + obj->insert("rfBandwidth", QJsonValue(rf_bandwidth)); + } + if(m_gain_isSet){ + obj->insert("gain", QJsonValue(gain)); + } + if(m_channel_mute_isSet){ + obj->insert("channelMute", QJsonValue(channel_mute)); + } + if(m_repeat_isSet){ + obj->insert("repeat", QJsonValue(repeat)); + } + if(m_repeat_count_isSet){ + obj->insert("repeatCount", QJsonValue(repeat_count)); + } + if(m_lpf_taps_isSet){ + obj->insert("lpfTaps", QJsonValue(lpf_taps)); + } + if(m_rf_noise_isSet){ + obj->insert("rfNoise", QJsonValue(rf_noise)); + } + if(text != nullptr && *text != QString("")){ + toJsonValue(QString("text"), text, obj, QString("QString")); + } + if(m_pulse_shaping_isSet){ + obj->insert("pulseShaping", QJsonValue(pulse_shaping)); + } + if(m_beta_isSet){ + obj->insert("beta", QJsonValue(beta)); + } + if(m_symbol_span_isSet){ + obj->insert("symbolSpan", QJsonValue(symbol_span)); + } + if(m_prefix_crlf_isSet){ + obj->insert("prefixCRLF", QJsonValue(prefix_crlf)); + } + if(m_postfix_crlf_isSet){ + obj->insert("postfixCRLF", QJsonValue(postfix_crlf)); + } + if(m_udp_enabled_isSet){ + obj->insert("udpEnabled", QJsonValue(udp_enabled)); + } + if(udp_address != nullptr && *udp_address != QString("")){ + toJsonValue(QString("udpAddress"), udp_address, obj, QString("QString")); + } + if(m_udp_port_isSet){ + obj->insert("udpPort", QJsonValue(udp_port)); + } + if(m_rgb_color_isSet){ + obj->insert("rgbColor", QJsonValue(rgb_color)); + } + if(title != nullptr && *title != QString("")){ + toJsonValue(QString("title"), title, obj, QString("QString")); + } + if(m_stream_index_isSet){ + obj->insert("streamIndex", QJsonValue(stream_index)); + } + if(m_use_reverse_api_isSet){ + obj->insert("useReverseAPI", QJsonValue(use_reverse_api)); + } + if(reverse_api_address != nullptr && *reverse_api_address != QString("")){ + toJsonValue(QString("reverseAPIAddress"), reverse_api_address, obj, QString("QString")); + } + if(m_reverse_api_port_isSet){ + obj->insert("reverseAPIPort", QJsonValue(reverse_api_port)); + } + if(m_reverse_api_device_index_isSet){ + obj->insert("reverseAPIDeviceIndex", QJsonValue(reverse_api_device_index)); + } + if(m_reverse_api_channel_index_isSet){ + obj->insert("reverseAPIChannelIndex", QJsonValue(reverse_api_channel_index)); + } + if((channel_marker != nullptr) && (channel_marker->isSet())){ + toJsonValue(QString("channelMarker"), channel_marker, obj, QString("SWGChannelMarker")); + } + if((rollup_state != nullptr) && (rollup_state->isSet())){ + toJsonValue(QString("rollupState"), rollup_state, obj, QString("SWGRollupState")); + } + + return obj; +} + +qint64 +SWGPSK31ModSettings::getInputFrequencyOffset() { + return input_frequency_offset; +} +void +SWGPSK31ModSettings::setInputFrequencyOffset(qint64 input_frequency_offset) { + this->input_frequency_offset = input_frequency_offset; + this->m_input_frequency_offset_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getRfBandwidth() { + return rf_bandwidth; +} +void +SWGPSK31ModSettings::setRfBandwidth(qint32 rf_bandwidth) { + this->rf_bandwidth = rf_bandwidth; + this->m_rf_bandwidth_isSet = true; +} + +float +SWGPSK31ModSettings::getGain() { + return gain; +} +void +SWGPSK31ModSettings::setGain(float gain) { + this->gain = gain; + this->m_gain_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getChannelMute() { + return channel_mute; +} +void +SWGPSK31ModSettings::setChannelMute(qint32 channel_mute) { + this->channel_mute = channel_mute; + this->m_channel_mute_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getRepeat() { + return repeat; +} +void +SWGPSK31ModSettings::setRepeat(qint32 repeat) { + this->repeat = repeat; + this->m_repeat_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getRepeatCount() { + return repeat_count; +} +void +SWGPSK31ModSettings::setRepeatCount(qint32 repeat_count) { + this->repeat_count = repeat_count; + this->m_repeat_count_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getLpfTaps() { + return lpf_taps; +} +void +SWGPSK31ModSettings::setLpfTaps(qint32 lpf_taps) { + this->lpf_taps = lpf_taps; + this->m_lpf_taps_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getRfNoise() { + return rf_noise; +} +void +SWGPSK31ModSettings::setRfNoise(qint32 rf_noise) { + this->rf_noise = rf_noise; + this->m_rf_noise_isSet = true; +} + +QString* +SWGPSK31ModSettings::getText() { + return text; +} +void +SWGPSK31ModSettings::setText(QString* text) { + this->text = text; + this->m_text_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getPulseShaping() { + return pulse_shaping; +} +void +SWGPSK31ModSettings::setPulseShaping(qint32 pulse_shaping) { + this->pulse_shaping = pulse_shaping; + this->m_pulse_shaping_isSet = true; +} + +float +SWGPSK31ModSettings::getBeta() { + return beta; +} +void +SWGPSK31ModSettings::setBeta(float beta) { + this->beta = beta; + this->m_beta_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getSymbolSpan() { + return symbol_span; +} +void +SWGPSK31ModSettings::setSymbolSpan(qint32 symbol_span) { + this->symbol_span = symbol_span; + this->m_symbol_span_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getPrefixCrlf() { + return prefix_crlf; +} +void +SWGPSK31ModSettings::setPrefixCrlf(qint32 prefix_crlf) { + this->prefix_crlf = prefix_crlf; + this->m_prefix_crlf_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getPostfixCrlf() { + return postfix_crlf; +} +void +SWGPSK31ModSettings::setPostfixCrlf(qint32 postfix_crlf) { + this->postfix_crlf = postfix_crlf; + this->m_postfix_crlf_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getUdpEnabled() { + return udp_enabled; +} +void +SWGPSK31ModSettings::setUdpEnabled(qint32 udp_enabled) { + this->udp_enabled = udp_enabled; + this->m_udp_enabled_isSet = true; +} + +QString* +SWGPSK31ModSettings::getUdpAddress() { + return udp_address; +} +void +SWGPSK31ModSettings::setUdpAddress(QString* udp_address) { + this->udp_address = udp_address; + this->m_udp_address_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getUdpPort() { + return udp_port; +} +void +SWGPSK31ModSettings::setUdpPort(qint32 udp_port) { + this->udp_port = udp_port; + this->m_udp_port_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getRgbColor() { + return rgb_color; +} +void +SWGPSK31ModSettings::setRgbColor(qint32 rgb_color) { + this->rgb_color = rgb_color; + this->m_rgb_color_isSet = true; +} + +QString* +SWGPSK31ModSettings::getTitle() { + return title; +} +void +SWGPSK31ModSettings::setTitle(QString* title) { + this->title = title; + this->m_title_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getStreamIndex() { + return stream_index; +} +void +SWGPSK31ModSettings::setStreamIndex(qint32 stream_index) { + this->stream_index = stream_index; + this->m_stream_index_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getUseReverseApi() { + return use_reverse_api; +} +void +SWGPSK31ModSettings::setUseReverseApi(qint32 use_reverse_api) { + this->use_reverse_api = use_reverse_api; + this->m_use_reverse_api_isSet = true; +} + +QString* +SWGPSK31ModSettings::getReverseApiAddress() { + return reverse_api_address; +} +void +SWGPSK31ModSettings::setReverseApiAddress(QString* reverse_api_address) { + this->reverse_api_address = reverse_api_address; + this->m_reverse_api_address_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getReverseApiPort() { + return reverse_api_port; +} +void +SWGPSK31ModSettings::setReverseApiPort(qint32 reverse_api_port) { + this->reverse_api_port = reverse_api_port; + this->m_reverse_api_port_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getReverseApiDeviceIndex() { + return reverse_api_device_index; +} +void +SWGPSK31ModSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) { + this->reverse_api_device_index = reverse_api_device_index; + this->m_reverse_api_device_index_isSet = true; +} + +qint32 +SWGPSK31ModSettings::getReverseApiChannelIndex() { + return reverse_api_channel_index; +} +void +SWGPSK31ModSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) { + this->reverse_api_channel_index = reverse_api_channel_index; + this->m_reverse_api_channel_index_isSet = true; +} + +SWGChannelMarker* +SWGPSK31ModSettings::getChannelMarker() { + return channel_marker; +} +void +SWGPSK31ModSettings::setChannelMarker(SWGChannelMarker* channel_marker) { + this->channel_marker = channel_marker; + this->m_channel_marker_isSet = true; +} + +SWGRollupState* +SWGPSK31ModSettings::getRollupState() { + return rollup_state; +} +void +SWGPSK31ModSettings::setRollupState(SWGRollupState* rollup_state) { + this->rollup_state = rollup_state; + this->m_rollup_state_isSet = true; +} + + +bool +SWGPSK31ModSettings::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_input_frequency_offset_isSet){ + isObjectUpdated = true; break; + } + if(m_rf_bandwidth_isSet){ + isObjectUpdated = true; break; + } + if(m_gain_isSet){ + isObjectUpdated = true; break; + } + if(m_channel_mute_isSet){ + isObjectUpdated = true; break; + } + if(m_repeat_isSet){ + isObjectUpdated = true; break; + } + if(m_repeat_count_isSet){ + isObjectUpdated = true; break; + } + if(m_lpf_taps_isSet){ + isObjectUpdated = true; break; + } + if(m_rf_noise_isSet){ + isObjectUpdated = true; break; + } + if(text && *text != QString("")){ + isObjectUpdated = true; break; + } + if(m_pulse_shaping_isSet){ + isObjectUpdated = true; break; + } + if(m_beta_isSet){ + isObjectUpdated = true; break; + } + if(m_symbol_span_isSet){ + isObjectUpdated = true; break; + } + if(m_prefix_crlf_isSet){ + isObjectUpdated = true; break; + } + if(m_postfix_crlf_isSet){ + isObjectUpdated = true; break; + } + if(m_udp_enabled_isSet){ + isObjectUpdated = true; break; + } + if(udp_address && *udp_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_udp_port_isSet){ + isObjectUpdated = true; break; + } + if(m_rgb_color_isSet){ + isObjectUpdated = true; break; + } + if(title && *title != QString("")){ + isObjectUpdated = true; break; + } + if(m_stream_index_isSet){ + isObjectUpdated = true; break; + } + if(m_use_reverse_api_isSet){ + isObjectUpdated = true; break; + } + if(reverse_api_address && *reverse_api_address != QString("")){ + isObjectUpdated = true; break; + } + if(m_reverse_api_port_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_device_index_isSet){ + isObjectUpdated = true; break; + } + if(m_reverse_api_channel_index_isSet){ + isObjectUpdated = true; break; + } + if(channel_marker && channel_marker->isSet()){ + isObjectUpdated = true; break; + } + if(rollup_state && rollup_state->isSet()){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGPSK31ModSettings.h b/swagger/sdrangel/code/qt5/client/SWGPSK31ModSettings.h new file mode 100644 index 0000000000..e933f8cb25 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGPSK31ModSettings.h @@ -0,0 +1,217 @@ +/** + * 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: 7.0.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. + */ + +/* + * SWGPSK31ModSettings.h + * + * PSK31Mod + */ + +#ifndef SWGPSK31ModSettings_H_ +#define SWGPSK31ModSettings_H_ + +#include + + +#include "SWGChannelMarker.h" +#include "SWGRollupState.h" +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGPSK31ModSettings: public SWGObject { +public: + SWGPSK31ModSettings(); + SWGPSK31ModSettings(QString* json); + virtual ~SWGPSK31ModSettings(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGPSK31ModSettings* fromJson(QString &jsonString) override; + + qint64 getInputFrequencyOffset(); + void setInputFrequencyOffset(qint64 input_frequency_offset); + + qint32 getRfBandwidth(); + void setRfBandwidth(qint32 rf_bandwidth); + + float getGain(); + void setGain(float gain); + + qint32 getChannelMute(); + void setChannelMute(qint32 channel_mute); + + qint32 getRepeat(); + void setRepeat(qint32 repeat); + + qint32 getRepeatCount(); + void setRepeatCount(qint32 repeat_count); + + qint32 getLpfTaps(); + void setLpfTaps(qint32 lpf_taps); + + qint32 getRfNoise(); + void setRfNoise(qint32 rf_noise); + + QString* getText(); + void setText(QString* text); + + qint32 getPulseShaping(); + void setPulseShaping(qint32 pulse_shaping); + + float getBeta(); + void setBeta(float beta); + + qint32 getSymbolSpan(); + void setSymbolSpan(qint32 symbol_span); + + qint32 getPrefixCrlf(); + void setPrefixCrlf(qint32 prefix_crlf); + + qint32 getPostfixCrlf(); + void setPostfixCrlf(qint32 postfix_crlf); + + qint32 getUdpEnabled(); + void setUdpEnabled(qint32 udp_enabled); + + QString* getUdpAddress(); + void setUdpAddress(QString* udp_address); + + qint32 getUdpPort(); + void setUdpPort(qint32 udp_port); + + qint32 getRgbColor(); + void setRgbColor(qint32 rgb_color); + + QString* getTitle(); + void setTitle(QString* title); + + qint32 getStreamIndex(); + void setStreamIndex(qint32 stream_index); + + 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); + + qint32 getReverseApiChannelIndex(); + void setReverseApiChannelIndex(qint32 reverse_api_channel_index); + + SWGChannelMarker* getChannelMarker(); + void setChannelMarker(SWGChannelMarker* channel_marker); + + SWGRollupState* getRollupState(); + void setRollupState(SWGRollupState* rollup_state); + + + virtual bool isSet() override; + +private: + qint64 input_frequency_offset; + bool m_input_frequency_offset_isSet; + + qint32 rf_bandwidth; + bool m_rf_bandwidth_isSet; + + float gain; + bool m_gain_isSet; + + qint32 channel_mute; + bool m_channel_mute_isSet; + + qint32 repeat; + bool m_repeat_isSet; + + qint32 repeat_count; + bool m_repeat_count_isSet; + + qint32 lpf_taps; + bool m_lpf_taps_isSet; + + qint32 rf_noise; + bool m_rf_noise_isSet; + + QString* text; + bool m_text_isSet; + + qint32 pulse_shaping; + bool m_pulse_shaping_isSet; + + float beta; + bool m_beta_isSet; + + qint32 symbol_span; + bool m_symbol_span_isSet; + + qint32 prefix_crlf; + bool m_prefix_crlf_isSet; + + qint32 postfix_crlf; + bool m_postfix_crlf_isSet; + + qint32 udp_enabled; + bool m_udp_enabled_isSet; + + QString* udp_address; + bool m_udp_address_isSet; + + qint32 udp_port; + bool m_udp_port_isSet; + + qint32 rgb_color; + bool m_rgb_color_isSet; + + QString* title; + bool m_title_isSet; + + qint32 stream_index; + bool m_stream_index_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; + + qint32 reverse_api_channel_index; + bool m_reverse_api_channel_index_isSet; + + SWGChannelMarker* channel_marker; + bool m_channel_marker_isSet; + + SWGRollupState* rollup_state; + bool m_rollup_state_isSet; + +}; + +} + +#endif /* SWGPSK31ModSettings_H_ */