diff --git a/plugins/channelrx/CMakeLists.txt b/plugins/channelrx/CMakeLists.txt index 4ed6a0cac..94e312d24 100644 --- a/plugins/channelrx/CMakeLists.txt +++ b/plugins/channelrx/CMakeLists.txt @@ -91,6 +91,7 @@ endif() if (ENABLE_CHANNELRX_DEMODFREEDV AND CODEC2_FOUND) add_subdirectory(demodfreedv) + add_subdirectory(demodm17) endif(CODEC2_FOUND) if (ENABLE_CHANNELRX_SIGMFFILESINK AND LIBSIGMF_FOUND AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") diff --git a/plugins/channelrx/demodm17/CMakeLists.txt b/plugins/channelrx/demodm17/CMakeLists.txt new file mode 100644 index 000000000..f7e92cff0 --- /dev/null +++ b/plugins/channelrx/demodm17/CMakeLists.txt @@ -0,0 +1,74 @@ +project(demodm17) + +set(m17_SOURCES + m17demod.cpp + m17demodbaseband.cpp + m17demodsink.cpp + m17demodsettings.cpp + m17demodwebapiadapter.cpp + m17demodplugin.cpp + m17demodbaudrates.cpp +) + +set(m17_HEADERS + m17demod.h + m17demodbaseband.h + m17demodsink.h + m17demodsettings.h + m17demodwebapiadapter.h + m17demodplugin.h + m17demodbaudrates.h +) + +include_directories( + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${CODEC2_INCLUDE_DIR} +) + +if(NOT SERVER_MODE) + set(m17_SOURCES + ${m17_SOURCES} + m17demodgui.cpp + m17demodgui.ui + m17statustextdialog.cpp + m17statustextdialog.ui + ) + set(m17_HEADERS + ${m17_HEADERS} + m17demodgui.h + m17statustextdialog.h + ) + set(TARGET_NAME demodm17) + set(TARGET_LIB "Qt5::Widgets") + set(TARGET_LIB_GUI "sdrgui") + set(INSTALL_FOLDER ${INSTALL_PLUGINS_DIR}) +else() + set(TARGET_NAME demodm17srv) + set(TARGET_LIB "") + set(TARGET_LIB_GUI "") + set(INSTALL_FOLDER ${INSTALL_PLUGINSSRV_DIR}) +endif() + +add_library(${TARGET_NAME} SHARED + ${m17_SOURCES} +) + +if(CODEC2_EXTERNAL) + add_dependencies(${TARGET_NAME} codec2) +endif() + +target_link_libraries(${TARGET_NAME} + Qt5::Core + ${TARGET_LIB} + sdrbase + ${TARGET_LIB_GUI} + swagger + ${CODEC2_LIBRARIES} +) + +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/channelrx/demodm17/m17demod.cpp b/plugins/channelrx/demodm17/m17demod.cpp new file mode 100644 index 000000000..307a36e27 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demod.cpp @@ -0,0 +1,729 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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 "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "device/deviceapi.h" +#include "feature/feature.h" +#include "feature/featureset.h" +#include "settings/serializable.h" +#include "util/db.h" +#include "maincore.h" + +#include "m17demod.h" + +MESSAGE_CLASS_DEFINITION(M17Demod::MsgConfigureM17Demod, Message) + +const char* const M17Demod::m_channelIdURI = "sdrangel.channel.m17demod"; +const char* const M17Demod::m_channelId = "M17Demod"; +const int M17Demod::m_udpBlockSize = 512; + +M17Demod::M17Demod(DeviceAPI *deviceAPI) : + ChannelAPI(m_channelIdURI, ChannelAPI::StreamSingleSink), + m_deviceAPI(deviceAPI), + m_basebandSampleRate(0) +{ + qDebug("M17Demod::M17Demod"); + setObjectName(m_channelId); + + m_thread = new QThread(this); + m_basebandSink = new M17DemodBaseband(); + m_basebandSink->setChannel(this); + m_basebandSink->moveToThread(m_thread); + + applySettings(m_settings, true); + + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + + m_networkManager = new QNetworkAccessManager(); + QObject::connect( + m_networkManager, + &QNetworkAccessManager::finished, + this, + &M17Demod::networkManagerFinished + ); + QObject::connect( + this, + &ChannelAPI::indexInDeviceSetChanged, + this, + &M17Demod::handleIndexInDeviceSetChanged + ); +} + +M17Demod::~M17Demod() +{ + QObject::disconnect( + m_networkManager, + &QNetworkAccessManager::finished, + this, + &M17Demod::networkManagerFinished + ); + delete m_networkManager; + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + delete m_basebandSink; + delete m_thread; +} + +void M17Demod::setDeviceAPI(DeviceAPI *deviceAPI) +{ + if (deviceAPI != m_deviceAPI) + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this); + m_deviceAPI = deviceAPI; + m_deviceAPI->addChannelSink(this); + m_deviceAPI->addChannelSinkAPI(this); + } +} + +uint32_t M17Demod::getNumberOfDeviceStreams() const +{ + return m_deviceAPI->getNbSourceStreams(); +} + +void M17Demod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst) +{ + (void) firstOfBurst; + m_basebandSink->feed(begin, end); +} + +void M17Demod::start() +{ + qDebug() << "M17Demod::start"; + + if (m_basebandSampleRate != 0) { + m_basebandSink->setBasebandSampleRate(m_basebandSampleRate); + } + + m_basebandSink->reset(); + m_thread->start(); +} + +void M17Demod::stop() +{ + qDebug() << "M17Demod::stop"; + m_thread->exit(); + m_thread->wait(); +} + +bool M17Demod::handleMessage(const Message& cmd) +{ + qDebug() << "M17Demod::handleMessage"; + + if (MsgConfigureM17Demod::match(cmd)) + { + MsgConfigureM17Demod& cfg = (MsgConfigureM17Demod&) cmd; + qDebug("M17Demod::handleMessage: MsgConfigureM17Demod"); + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (DSPSignalNotification::match(cmd)) + { + DSPSignalNotification& notif = (DSPSignalNotification&) cmd; + m_basebandSampleRate = notif.getSampleRate(); + // Forward to the sink + DSPSignalNotification* rep = new DSPSignalNotification(notif); // make a copy + qDebug() << "M17Demod::handleMessage: DSPSignalNotification"; + m_basebandSink->getInputMessageQueue()->push(rep); + // Forward to GUI if any + if (getMessageQueueToGUI()) { + getMessageQueueToGUI()->push(new DSPSignalNotification(notif)); + } + + return true; + } + else if (MainCore::MsgChannelDemodQuery::match(cmd)) + { + qDebug() << "M17Demod::handleMessage: MsgChannelDemodQuery"; + sendSampleRateToDemodAnalyzer(); + + return true; + } + else + { + return false; + } +} + +void M17Demod::setCenterFrequency(qint64 frequency) +{ + M17DemodSettings settings = m_settings; + settings.m_inputFrequencyOffset = frequency; + applySettings(settings, false); + + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigureM17Demod *msgToGUI = MsgConfigureM17Demod::create(settings, false); + m_guiMessageQueue->push(msgToGUI); + } +} + +void M17Demod::applySettings(const M17DemodSettings& settings, bool force) +{ + qDebug() << "M17Demod::applySettings: " + << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset + << " m_rfBandwidth: " << settings.m_rfBandwidth + << " m_fmDeviation: " << settings.m_fmDeviation + << " m_demodGain: " << settings.m_demodGain + << " m_volume: " << settings.m_volume + << " m_baudRate: " << settings.m_baudRate + << " m_squelchGate" << settings.m_squelchGate + << " m_squelch: " << settings.m_squelch + << " m_audioMute: " << settings.m_audioMute + << " m_syncOrConstellation: " << settings.m_syncOrConstellation + << " m_highPassFilter: "<< settings.m_highPassFilter + << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_traceLengthMutliplier: " << settings.m_traceLengthMutliplier + << " m_traceStroke: " << settings.m_traceStroke + << " m_traceDecay: " << settings.m_traceDecay + << " m_streamIndex: " << settings.m_streamIndex + << " force: " << force; + + QList reverseAPIKeys; + + if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) { + reverseAPIKeys.append("inputFrequencyOffset"); + } + if ((settings.m_demodGain != m_settings.m_demodGain) || force) { + reverseAPIKeys.append("demodGain"); + } + if ((settings.m_audioMute != m_settings.m_audioMute) || force) { + reverseAPIKeys.append("audioMute"); + } + if ((settings.m_syncOrConstellation != m_settings.m_syncOrConstellation) || force) { + reverseAPIKeys.append("syncOrConstellation"); + } + if ((settings.m_demodGain != m_settings.m_demodGain) || force) { + reverseAPIKeys.append("demodGain"); + } + if ((settings.m_traceLengthMutliplier != m_settings.m_traceLengthMutliplier) || force) { + reverseAPIKeys.append("traceLengthMutliplier"); + } + if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) { + reverseAPIKeys.append("rfBandwidth"); + } + if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) { + reverseAPIKeys.append("fmDeviation"); + } + if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) { + reverseAPIKeys.append("squelchGate"); + } + if ((settings.m_squelch != m_settings.m_squelch) || force) { + reverseAPIKeys.append("squelch"); + } + if ((settings.m_volume != m_settings.m_volume) || force) { + reverseAPIKeys.append("volume"); + } + if ((settings.m_baudRate != m_settings.m_baudRate) || force) { + reverseAPIKeys.append("baudRate"); + } + if ((settings.m_highPassFilter != m_settings.m_highPassFilter) || force) { + reverseAPIKeys.append("highPassFilter"); + } + if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) { + reverseAPIKeys.append("audioDeviceName"); + } + + if (m_settings.m_streamIndex != settings.m_streamIndex) + { + if (m_deviceAPI->getSampleMIMO()) // change of stream is possible for MIMO devices only + { + m_deviceAPI->removeChannelSinkAPI(this); + m_deviceAPI->removeChannelSink(this, m_settings.m_streamIndex); + m_deviceAPI->addChannelSink(this, settings.m_streamIndex); + m_deviceAPI->addChannelSinkAPI(this); + } + + reverseAPIKeys.append("streamIndex"); + } + + M17DemodBaseband::MsgConfigureM17DemodBaseband *msg = M17DemodBaseband::MsgConfigureM17DemodBaseband::create(settings, force); + m_basebandSink->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 M17Demod::serialize() const +{ + return m_settings.serialize(); +} + +bool M17Demod::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + MsgConfigureM17Demod *msg = MsgConfigureM17Demod::create(m_settings, true); + m_inputMessageQueue.push(msg); + return true; + } + else + { + m_settings.resetToDefaults(); + MsgConfigureM17Demod *msg = MsgConfigureM17Demod::create(m_settings, true); + m_inputMessageQueue.push(msg); + return false; + } +} + +void M17Demod::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, + getAudioSampleRate() + ); + messageQueue->push(msg); + } + } +} + +int M17Demod::webapiSettingsGet( + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setM17DemodSettings(new SWGSDRangel::SWGM17DemodSettings()); + response.getM17DemodSettings()->init(); + webapiFormatChannelSettings(response, m_settings); + return 200; +} + +int M17Demod::webapiWorkspaceGet( + SWGSDRangel::SWGWorkspaceInfo& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setIndex(m_settings.m_workspaceIndex); + return 200; +} + +int M17Demod::webapiSettingsPutPatch( + bool force, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + M17DemodSettings settings = m_settings; + webapiUpdateChannelSettings(settings, channelSettingsKeys, response); + + MsgConfigureM17Demod *msg = MsgConfigureM17Demod::create(settings, force); + m_inputMessageQueue.push(msg); + + qDebug("M17Demod::webapiSettingsPutPatch: forward to GUI: %p", m_guiMessageQueue); + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigureM17Demod *msgToGUI = MsgConfigureM17Demod::create(settings, force); + m_guiMessageQueue->push(msgToGUI); + } + + webapiFormatChannelSettings(response, settings); + + return 200; +} + +void M17Demod::webapiUpdateChannelSettings( + M17DemodSettings& settings, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response) +{ + if (channelSettingsKeys.contains("inputFrequencyOffset")) { + settings.m_inputFrequencyOffset = response.getM17DemodSettings()->getInputFrequencyOffset(); + } + if (channelSettingsKeys.contains("rfBandwidth")) { + settings.m_rfBandwidth = response.getM17DemodSettings()->getRfBandwidth(); + } + if (channelSettingsKeys.contains("fmDeviation")) { + settings.m_fmDeviation = response.getM17DemodSettings()->getFmDeviation(); + } + if (channelSettingsKeys.contains("demodGain")) { + settings.m_demodGain = response.getM17DemodSettings()->getDemodGain(); + } + if (channelSettingsKeys.contains("volume")) { + settings.m_volume = response.getM17DemodSettings()->getVolume(); + } + if (channelSettingsKeys.contains("baudRate")) { + settings.m_baudRate = response.getM17DemodSettings()->getBaudRate(); + } + if (channelSettingsKeys.contains("squelchGate")) { + settings.m_squelchGate = response.getM17DemodSettings()->getSquelchGate(); + } + if (channelSettingsKeys.contains("squelch")) { + settings.m_squelch = response.getM17DemodSettings()->getSquelch(); + } + if (channelSettingsKeys.contains("audioMute")) { + settings.m_audioMute = response.getM17DemodSettings()->getAudioMute() != 0; + } + if (channelSettingsKeys.contains("syncOrConstellation")) { + settings.m_syncOrConstellation = response.getM17DemodSettings()->getSyncOrConstellation() != 0; + } + if (channelSettingsKeys.contains("rgbColor")) { + settings.m_rgbColor = response.getM17DemodSettings()->getRgbColor(); + } + if (channelSettingsKeys.contains("title")) { + settings.m_title = *response.getM17DemodSettings()->getTitle(); + } + if (channelSettingsKeys.contains("audioDeviceName")) { + settings.m_audioDeviceName = *response.getM17DemodSettings()->getAudioDeviceName(); + } + if (channelSettingsKeys.contains("highPassFilter")) { + settings.m_highPassFilter = response.getM17DemodSettings()->getHighPassFilter() != 0; + } + if (channelSettingsKeys.contains("traceLengthMutliplier")) { + settings.m_traceLengthMutliplier = response.getM17DemodSettings()->getTraceLengthMutliplier(); + } + if (channelSettingsKeys.contains("traceStroke")) { + settings.m_traceStroke = response.getM17DemodSettings()->getTraceStroke(); + } + if (channelSettingsKeys.contains("traceDecay")) { + settings.m_traceDecay = response.getM17DemodSettings()->getTraceDecay(); + } + if (channelSettingsKeys.contains("streamIndex")) { + settings.m_streamIndex = response.getM17DemodSettings()->getStreamIndex(); + } + if (channelSettingsKeys.contains("useReverseAPI")) { + settings.m_useReverseAPI = response.getM17DemodSettings()->getUseReverseApi() != 0; + } + if (channelSettingsKeys.contains("reverseAPIAddress")) { + settings.m_reverseAPIAddress = *response.getM17DemodSettings()->getReverseApiAddress(); + } + if (channelSettingsKeys.contains("reverseAPIPort")) { + settings.m_reverseAPIPort = response.getM17DemodSettings()->getReverseApiPort(); + } + if (channelSettingsKeys.contains("reverseAPIDeviceIndex")) { + settings.m_reverseAPIDeviceIndex = response.getM17DemodSettings()->getReverseApiDeviceIndex(); + } + if (channelSettingsKeys.contains("reverseAPIChannelIndex")) { + settings.m_reverseAPIChannelIndex = response.getM17DemodSettings()->getReverseApiChannelIndex(); + } + if (settings.m_channelMarker && channelSettingsKeys.contains("channelMarker")) { + settings.m_channelMarker->updateFrom(channelSettingsKeys, response.getM17DemodSettings()->getChannelMarker()); + } + if (settings.m_rollupState && channelSettingsKeys.contains("rollupState")) { + settings.m_rollupState->updateFrom(channelSettingsKeys, response.getM17DemodSettings()->getRollupState()); + } +} + +int M17Demod::webapiReportGet( + SWGSDRangel::SWGChannelReport& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setM17DemodReport(new SWGSDRangel::SWGM17DemodReport()); + response.getM17DemodReport()->init(); + webapiFormatChannelReport(response); + return 200; +} + +void M17Demod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const M17DemodSettings& settings) +{ + response.getM17DemodSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + response.getM17DemodSettings()->setRfBandwidth(settings.m_rfBandwidth); + response.getM17DemodSettings()->setFmDeviation(settings.m_fmDeviation); + response.getM17DemodSettings()->setDemodGain(settings.m_demodGain); + response.getM17DemodSettings()->setVolume(settings.m_volume); + response.getM17DemodSettings()->setBaudRate(settings.m_baudRate); + response.getM17DemodSettings()->setSquelchGate(settings.m_squelchGate); + response.getM17DemodSettings()->setSquelch(settings.m_squelch); + response.getM17DemodSettings()->setAudioMute(settings.m_audioMute ? 1 : 0); + response.getM17DemodSettings()->setSyncOrConstellation(settings.m_syncOrConstellation ? 1 : 0); + response.getM17DemodSettings()->setRgbColor(settings.m_rgbColor); + + if (response.getM17DemodSettings()->getTitle()) { + *response.getM17DemodSettings()->getTitle() = settings.m_title; + } else { + response.getM17DemodSettings()->setTitle(new QString(settings.m_title)); + } + + if (response.getM17DemodSettings()->getAudioDeviceName()) { + *response.getM17DemodSettings()->getAudioDeviceName() = settings.m_audioDeviceName; + } else { + response.getM17DemodSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); + } + + response.getM17DemodSettings()->setHighPassFilter(settings.m_highPassFilter ? 1 : 0); + response.getM17DemodSettings()->setTraceLengthMutliplier(settings.m_traceLengthMutliplier); + response.getM17DemodSettings()->setTraceStroke(settings.m_traceStroke); + response.getM17DemodSettings()->setTraceDecay(settings.m_traceDecay); + response.getM17DemodSettings()->setStreamIndex(settings.m_streamIndex); + response.getM17DemodSettings()->setUseReverseApi(settings.m_useReverseAPI ? 1 : 0); + + if (response.getM17DemodSettings()->getReverseApiAddress()) { + *response.getM17DemodSettings()->getReverseApiAddress() = settings.m_reverseAPIAddress; + } else { + response.getM17DemodSettings()->setReverseApiAddress(new QString(settings.m_reverseAPIAddress)); + } + + response.getM17DemodSettings()->setReverseApiPort(settings.m_reverseAPIPort); + response.getM17DemodSettings()->setReverseApiDeviceIndex(settings.m_reverseAPIDeviceIndex); + response.getM17DemodSettings()->setReverseApiChannelIndex(settings.m_reverseAPIChannelIndex); + + if (settings.m_channelMarker) + { + if (response.getM17DemodSettings()->getChannelMarker()) + { + settings.m_channelMarker->formatTo(response.getM17DemodSettings()->getChannelMarker()); + } + else + { + SWGSDRangel::SWGChannelMarker *swgChannelMarker = new SWGSDRangel::SWGChannelMarker(); + settings.m_channelMarker->formatTo(swgChannelMarker); + response.getM17DemodSettings()->setChannelMarker(swgChannelMarker); + } + } + + if (settings.m_rollupState) + { + if (response.getM17DemodSettings()->getRollupState()) + { + settings.m_rollupState->formatTo(response.getM17DemodSettings()->getRollupState()); + } + else + { + SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState(); + settings.m_rollupState->formatTo(swgRollupState); + response.getM17DemodSettings()->setRollupState(swgRollupState); + } + } +} + +void M17Demod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) +{ + double magsqAvg, magsqPeak; + int nbMagsqSamples; + getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples); + + response.getM17DemodReport()->setChannelPowerDb(CalcDb::dbPower(magsqAvg)); + response.getM17DemodReport()->setAudioSampleRate(m_basebandSink->getAudioSampleRate()); + response.getM17DemodReport()->setChannelSampleRate(m_basebandSink->getChannelSampleRate()); + response.getM17DemodReport()->setSquelch(m_basebandSink->getSquelchOpen() ? 1 : 0); +} + +void M17Demod::webapiReverseSendSettings(QList& channelSettingsKeys, const M17DemodSettings& 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 M17Demod::sendChannelSettings( + const QList& pipes, + QList& channelSettingsKeys, + const M17DemodSettings& 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 M17Demod::webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const M17DemodSettings& settings, + bool force +) +{ + swgChannelSettings->setDirection(0); // Single sink (Rx) + swgChannelSettings->setOriginatorChannelIndex(getIndexInDeviceSet()); + swgChannelSettings->setOriginatorDeviceSetIndex(getDeviceSetIndex()); + swgChannelSettings->setChannelType(new QString(m_channelId)); + swgChannelSettings->setM17DemodSettings(new SWGSDRangel::SWGM17DemodSettings()); + SWGSDRangel::SWGM17DemodSettings *swgM17DemodSettings = swgChannelSettings->getM17DemodSettings(); + + // transfer data that has been modified. When force is on transfer all data except reverse API data + + if (channelSettingsKeys.contains("inputFrequencyOffset") || force) { + swgM17DemodSettings->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + } + if (channelSettingsKeys.contains("rfBandwidth") || force) { + swgM17DemodSettings->setRfBandwidth(settings.m_rfBandwidth); + } + if (channelSettingsKeys.contains("fmDeviation") || force) { + swgM17DemodSettings->setFmDeviation(settings.m_fmDeviation); + } + if (channelSettingsKeys.contains("demodGain") || force) { + swgM17DemodSettings->setDemodGain(settings.m_demodGain); + } + if (channelSettingsKeys.contains("volume") || force) { + swgM17DemodSettings->setVolume(settings.m_volume); + } + if (channelSettingsKeys.contains("baudRate") || force) { + swgM17DemodSettings->setBaudRate(settings.m_baudRate); + } + if (channelSettingsKeys.contains("squelchGate") || force) { + swgM17DemodSettings->setSquelchGate(settings.m_squelchGate); + } + if (channelSettingsKeys.contains("squelch") || force) { + swgM17DemodSettings->setSquelch(settings.m_squelch); + } + if (channelSettingsKeys.contains("audioMute") || force) { + swgM17DemodSettings->setAudioMute(settings.m_audioMute ? 1 : 0); + } + if (channelSettingsKeys.contains("syncOrConstellation") || force) { + swgM17DemodSettings->setSyncOrConstellation(settings.m_syncOrConstellation ? 1 : 0); + } + if (channelSettingsKeys.contains("rgbColor") || force) { + swgM17DemodSettings->setRgbColor(settings.m_rgbColor); + } + if (channelSettingsKeys.contains("title") || force) { + swgM17DemodSettings->setTitle(new QString(settings.m_title)); + } + if (channelSettingsKeys.contains("audioDeviceName") || force) { + swgM17DemodSettings->setAudioDeviceName(new QString(settings.m_audioDeviceName)); + } + if (channelSettingsKeys.contains("highPassFilter") || force) { + swgM17DemodSettings->setHighPassFilter(settings.m_highPassFilter ? 1 : 0); + } + if (channelSettingsKeys.contains("traceLengthMutliplier") || force) { + swgM17DemodSettings->setTraceLengthMutliplier(settings.m_traceLengthMutliplier); + } + if (channelSettingsKeys.contains("traceStroke") || force) { + swgM17DemodSettings->setTraceStroke(settings.m_traceStroke); + } + if (channelSettingsKeys.contains("traceDecay") || force) { + swgM17DemodSettings->setTraceDecay(settings.m_traceDecay); + } + if (channelSettingsKeys.contains("streamIndex") || force) { + swgM17DemodSettings->setStreamIndex(settings.m_streamIndex); + } + + if (settings.m_channelMarker && (channelSettingsKeys.contains("channelMarker") || force)) + { + SWGSDRangel::SWGChannelMarker *swgChannelMarker = new SWGSDRangel::SWGChannelMarker(); + settings.m_channelMarker->formatTo(swgChannelMarker); + swgM17DemodSettings->setChannelMarker(swgChannelMarker); + } + + if (settings.m_rollupState && (channelSettingsKeys.contains("rollupState") || force)) + { + SWGSDRangel::SWGRollupState *swgRollupState = new SWGSDRangel::SWGRollupState(); + settings.m_rollupState->formatTo(swgRollupState); + swgM17DemodSettings->setRollupState(swgRollupState); + } +} + +void M17Demod::networkManagerFinished(QNetworkReply *reply) +{ + QNetworkReply::NetworkError replyError = reply->error(); + + if (replyError) + { + qWarning() << "M17Demod::networkManagerFinished:" + << " error(" << (int) replyError + << "): " << replyError + << ": " << reply->errorString(); + } + else + { + QString answer = reply->readAll(); + answer.chop(1); // remove last \n + qDebug("M17Demod::networkManagerFinished: reply:\n%s", answer.toStdString().c_str()); + } + + reply->deleteLater(); +} + +void M17Demod::handleIndexInDeviceSetChanged(int index) +{ + if (index < 0) { + return; + } + + QString fifoLabel = QString("%1 [%2:%3]") + .arg(m_channelId) + .arg(m_deviceAPI->getDeviceSetIndex()) + .arg(index); + m_basebandSink->setFifoLabel(fifoLabel); + m_basebandSink->setAudioFifoLabel(fifoLabel); +} diff --git a/plugins/channelrx/demodm17/m17demod.h b/plugins/channelrx/demodm17/m17demod.h new file mode 100644 index 000000000..788f3b7fb --- /dev/null +++ b/plugins/channelrx/demodm17/m17demod.h @@ -0,0 +1,169 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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_M17DEMOD_H +#define INCLUDE_M17DEMOD_H + +#include + +#include + +#include "dsp/basebandsamplesink.h" +#include "channel/channelapi.h" +#include "util/message.h" + +#include "m17demodsettings.h" +#include "m17demodbaseband.h" + +class QNetworkAccessManager; +class QNetworkReply; +class QThread; +class DownChannelizer; +class ObjectPipe; + +class M17Demod : public BasebandSampleSink, public ChannelAPI { +public: + class MsgConfigureM17Demod : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const M17DemodSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureM17Demod* create(const M17DemodSettings& settings, bool force) + { + return new MsgConfigureM17Demod(settings, force); + } + + private: + M17DemodSettings m_settings; + bool m_force; + + MsgConfigureM17Demod(const M17DemodSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + M17Demod(DeviceAPI *deviceAPI); + virtual ~M17Demod(); + virtual void destroy() { delete this; } + virtual void setDeviceAPI(DeviceAPI *deviceAPI); + virtual DeviceAPI *getDeviceAPI() { return m_deviceAPI; } + + using BasebandSampleSink::feed; + virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); + virtual void start(); + virtual void stop(); + virtual void pushMessage(Message *msg) { m_inputMessageQueue.push(msg); } + virtual QString getSinkName() { 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); + + static void webapiFormatChannelSettings( + SWGSDRangel::SWGChannelSettings& response, + const M17DemodSettings& settings); + + static void webapiUpdateChannelSettings( + M17DemodSettings& settings, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response); + + uint32_t getNumberOfDeviceStreams() const; + void setScopeXYSink(BasebandSampleSink* sampleSink) { m_basebandSink->setScopeXYSink(sampleSink); } + void configureMyPosition(float myLatitude, float myLongitude) { m_basebandSink->configureMyPosition(myLatitude, myLongitude); } + double getMagSq() { return m_basebandSink->getMagSq(); } + bool getSquelchOpen() const { return m_basebandSink->getSquelchOpen(); } + void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_basebandSink->getMagSqLevels(avg, peak, nbSamples); } + int getAudioSampleRate() const { return m_basebandSink->getAudioSampleRate(); } + + static const char* const m_channelIdURI; + static const char* const m_channelId; + +private: + DeviceAPI *m_deviceAPI; + QThread *m_thread; + M17DemodBaseband *m_basebandSink; + M17DemodSettings m_settings; + int m_basebandSampleRate; //!< stored from device message used when starting baseband sink + + QNetworkAccessManager *m_networkManager; + QNetworkRequest m_networkRequest; + + static const int m_udpBlockSize; + + virtual bool handleMessage(const Message& cmd); + void applySettings(const M17DemodSettings& settings, bool force = false); + void sendSampleRateToDemodAnalyzer(); + void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); + void webapiReverseSendSettings(QList& channelSettingsKeys, const M17DemodSettings& settings, bool force); + void sendChannelSettings( + const QList& pipes, + QList& channelSettingsKeys, + const M17DemodSettings& settings, + bool force + ); + void webapiFormatChannelSettings( + QList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings *swgChannelSettings, + const M17DemodSettings& settings, + bool force + ); + +private slots: + void networkManagerFinished(QNetworkReply *reply); + void handleIndexInDeviceSetChanged(int index); +}; + +#endif // INCLUDE_M17DEMOD_H diff --git a/plugins/channelrx/demodm17/m17demod.ui b/plugins/channelrx/demodm17/m17demod.ui new file mode 100644 index 000000000..ab952edff --- /dev/null +++ b/plugins/channelrx/demodm17/m17demod.ui @@ -0,0 +1,1169 @@ + + + M17DemodGUI + + + + 0 + 0 + 482 + 392 + + + + + 0 + 0 + + + + + 482 + 392 + + + + + 750 + 392 + + + + + Liberation Sans + 9 + + + + M17 Demodulator + + + + + 0 + 0 + 480 + 172 + + + + + 0 + 0 + + + + + 480 + 0 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + 2 + + + + + 6 + + + + + + 16 + 0 + + + + Df + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Demod shift frequency from center in Hz + + + + + + + Hz + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + RFBW + + + + + + + Bandwidth (kHz) before discriminator + + + 500 + + + 1 + + + 100 + + + Qt::Horizontal + + + + + + + + 40 + 0 + + + + 00.0k + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + Channel power (dB) + + + Qt::RightToLeft + + + -100.0 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Level meter (dB) top trace: average, bottom trace: instantaneous peak, tip: peak hold + + + dB + + + + + + + + 0 + 0 + + + + + 0 + 24 + + + + + Liberation Mono + 8 + + + + + + + + + + + + Activate status text log + + + + + + + + + + + 24 + 0 + + + + + 24 + 16777215 + + + + View status text log + + + + + + + :/listing.png:/listing.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + + + + Vol + + + + + + + + 24 + 24 + + + + Sound volume + + + 100 + + + 1 + + + 20 + + + + + + + + 30 + 0 + + + + + 30 + 16777215 + + + + Sound volume + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + + + + + Sq + + + + + + + + 24 + 24 + + + + Squelch threshold (dB) + + + -100 + + + 0 + + + 1 + + + 1 + + + -40 + + + + + + + + 30 + 0 + + + + Squelch threshold (dB) + + + -100 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 24 + 24 + + + + Squelch gate (ms) + + + 0 + + + 50 + + + 1 + + + 5 + + + 5 + + + + + + + + 25 + 0 + + + + Squelch gate (ms) + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Toggle audio high pass filter + + + + + + + :/filter_highpass.png:/filter_highpass.png + + + + + + + Left: Mute/Unmute audio (all slots) Right: select audio output + + + ... + + + + :/sound_on.png + :/sound_off.png:/sound_on.png + + + true + + + + + + + + + 2 + + + 2 + + + 2 + + + + + Source + + + + + + + + 80 + 0 + + + + ... + + + + + + + Dest + + + + + + + + 80 + 0 + + + + ... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 0 + 180 + 480 + 210 + + + + + 480 + 210 + + + + Digital + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + 200 + 200 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 59 + 20 + + + + + 0 + 0 + + + + + 35 + 0 + + + + + 16777215 + 16777215 + + + + Baud rate: 2.4k: NXDN48, dPMR 4.8k: DMR, D-Star, YSF, NXDN96 + + + + 4.8k + + + + + + + 80 + 10 + 110 + 25 + + + + + 110 + 0 + + + + + 16777215 + 25 + + + + + Liberation Mono + 9 + + + + Synchronized on this frame type + + + QFrame::Box + + + QFrame::Sunken + + + 2 + + + No Sync______ + + + + + + 10 + 40 + 25 + 28 + + + + + 25 + 0 + + + + Symbol synchronization rate (%) + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 40 + 40 + 25 + 28 + + + + + 25 + 0 + + + + Zero crossing relative position in number of samples (<0 sampling point lags, >0 it leads) + + + -00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 80 + 40 + 25 + 28 + + + + + 25 + 0 + + + + Carrier relative position (%) when synchronized + + + -00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 110 + 40 + 25 + 28 + + + + + 25 + 0 + + + + Carrier input level (%) when synchronized + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 70 + 23 + 22 + + + + Toggle between transition constellation and symbol synchronization displays + + + + + + + :/constellation.png + :/slopep_icon.png:/constellation.png + + + true + + + + + + 50 + 107 + 141 + 16 + + + + Maximum frequency deviation (kHz) + + + 100 + + + 1 + + + 35 + + + 35 + + + Qt::Horizontal + + + + + + 10 + 100 + 25 + 29 + + + + FMd + + + + + + 200 + 100 + 50 + 29 + + + + + 50 + 0 + + + + +00.0k + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 130 + 28 + 30 + + + + Gain + + + + + + 50 + 137 + 141 + 16 + + + + + 0 + 0 + + + + Gain after discriminator + + + 50 + + + 200 + + + 1 + + + 100 + + + Qt::Horizontal + + + + + + 40 + 68 + 24 + 24 + + + + + 24 + 24 + + + + Display trace length (ms) + + + 6 + + + 30 + + + 1 + + + 6 + + + + + + 70 + 73 + 31 + 16 + + + + Display trace length (ms) + + + 0000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 200 + 130 + 50 + 29 + + + + + 50 + 0 + + + + 0.00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 110 + 70 + 24 + 24 + + + + + 24 + 24 + + + + Trace stroke [0..255] + + + 0 + + + 255 + + + 1 + + + 100 + + + + + + 130 + 73 + 31 + 16 + + + + Trace stroke value + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 170 + 70 + 24 + 24 + + + + + 24 + 24 + + + + Trace decay [0..255] + + + 0 + + + 255 + + + 1 + + + 200 + + + + + + 190 + 73 + 31 + 16 + + + + Trace decay value + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + LevelMeterSignalDB + QWidget +
gui/levelmeter.h
+ 1 +
+ + TVScreen + QWidget +
gui/tvscreen.h
+ 1 +
+
+ + + + +
diff --git a/plugins/channelrx/demodm17/m17demodbaseband.cpp b/plugins/channelrx/demodm17/m17demodbaseband.cpp new file mode 100644 index 000000000..b2047142b --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodbaseband.cpp @@ -0,0 +1,190 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2019 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +#include "dsp/dspengine.h" +#include "dsp/dspcommands.h" +#include "dsp/downchannelizer.h" + +#include "m17demodbaseband.h" + +MESSAGE_CLASS_DEFINITION(M17DemodBaseband::MsgConfigureM17DemodBaseband, Message) + +M17DemodBaseband::M17DemodBaseband() : + m_mutex(QMutex::Recursive) +{ + qDebug("M17DemodBaseband::M17DemodBaseband"); + m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(48000)); + m_channelizer = new DownChannelizer(&m_sink); + + QObject::connect( + &m_sampleFifo, + &SampleSinkFifo::dataReady, + this, + &M17DemodBaseband::handleData, + Qt::QueuedConnection + ); + + DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(m_sink.getAudioFifo(), getInputMessageQueue()); + m_sink.applyAudioSampleRate(DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate()); + m_channelSampleRate = 0; + + connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); +} + +M17DemodBaseband::~M17DemodBaseband() +{ + DSPEngine::instance()->getAudioDeviceManager()->removeAudioSink(m_sink.getAudioFifo()); + delete m_channelizer; +} + +void M17DemodBaseband::reset() +{ + QMutexLocker mutexLocker(&m_mutex); + m_sampleFifo.reset(); + m_channelSampleRate = 0; +} + +void M17DemodBaseband::setChannel(ChannelAPI *channel) +{ + m_sink.setChannel(channel); +} + +void M17DemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) +{ + m_sampleFifo.write(begin, end); +} + +void M17DemodBaseband::handleData() +{ + QMutexLocker mutexLocker(&m_mutex); + + while ((m_sampleFifo.fill() > 0) && (m_inputMessageQueue.size() == 0)) + { + SampleVector::iterator part1begin; + SampleVector::iterator part1end; + SampleVector::iterator part2begin; + SampleVector::iterator part2end; + + std::size_t count = m_sampleFifo.readBegin(m_sampleFifo.fill(), &part1begin, &part1end, &part2begin, &part2end); + + // first part of FIFO data + if (part1begin != part1end) { + m_channelizer->feed(part1begin, part1end); + } + + // second part of FIFO data (used when block wraps around) + if(part2begin != part2end) { + m_channelizer->feed(part2begin, part2end); + } + + m_sampleFifo.readCommit((unsigned int) count); + } +} + +void M17DemodBaseband::handleInputMessages() +{ + Message* message; + + while ((message = m_inputMessageQueue.pop()) != nullptr) + { + if (handleMessage(*message)) { + delete message; + } + } +} + +bool M17DemodBaseband::handleMessage(const Message& cmd) +{ + if (MsgConfigureM17DemodBaseband::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + MsgConfigureM17DemodBaseband& cfg = (MsgConfigureM17DemodBaseband&) cmd; + qDebug() << "M17DemodBaseband::handleMessage: MsgConfigureM17DemodBaseband"; + + applySettings(cfg.getSettings(), cfg.getForce()); + + return true; + } + else if (DSPSignalNotification::match(cmd)) + { + QMutexLocker mutexLocker(&m_mutex); + DSPSignalNotification& notif = (DSPSignalNotification&) cmd; + qDebug() << "M17DemodBaseband::handleMessage: DSPSignalNotification: basebandSampleRate: " << notif.getSampleRate(); + m_sampleFifo.setSize(SampleSinkFifo::getSizePolicy(notif.getSampleRate())); + m_channelizer->setBasebandSampleRate(notif.getSampleRate()); + m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); + + if (m_channelSampleRate != m_channelizer->getChannelSampleRate()) + { + m_sink.applyAudioSampleRate(m_sink.getAudioSampleRate()); // reapply when channel sample rate changes + m_channelSampleRate = m_channelizer->getChannelSampleRate(); + } + + return true; + } + else + { + return false; + } +} + +void M17DemodBaseband::applySettings(const M17DemodSettings& settings, bool force) +{ + if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) + { + m_channelizer->setChannelization(48000, settings.m_inputFrequencyOffset); + m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); + + if (m_channelSampleRate != m_channelizer->getChannelSampleRate()) + { + m_sink.applyAudioSampleRate(m_sink.getAudioSampleRate()); // reapply when channel sample rate changes + m_channelSampleRate = m_channelizer->getChannelSampleRate(); + } + } + + if ((settings.m_audioDeviceName != m_settings.m_audioDeviceName) || force) + { + AudioDeviceManager *audioDeviceManager = DSPEngine::instance()->getAudioDeviceManager(); + int audioDeviceIndex = audioDeviceManager->getOutputDeviceIndex(settings.m_audioDeviceName); + //qDebug("AMDemod::applySettings: audioDeviceName: %s audioDeviceIndex: %d", qPrintable(settings.m_audioDeviceName), audioDeviceIndex); + audioDeviceManager->removeAudioSink(m_sink.getAudioFifo()); + audioDeviceManager->addAudioSink(m_sink.getAudioFifo(), getInputMessageQueue(), audioDeviceIndex); + int audioSampleRate = audioDeviceManager->getOutputSampleRate(audioDeviceIndex); + + if (m_sink.getAudioSampleRate() != audioSampleRate) { + m_sink.applyAudioSampleRate(audioSampleRate); + } + } + + m_sink.applySettings(settings, force); + + m_settings = settings; +} + +int M17DemodBaseband::getChannelSampleRate() const +{ + return m_channelizer->getChannelSampleRate(); +} + + +void M17DemodBaseband::setBasebandSampleRate(int sampleRate) +{ + m_channelizer->setBasebandSampleRate(sampleRate); + m_sink.applyChannelSettings(m_channelizer->getChannelSampleRate(), m_channelizer->getChannelFrequencyOffset()); +} diff --git a/plugins/channelrx/demodm17/m17demodbaseband.h b/plugins/channelrx/demodm17/m17demodbaseband.h new file mode 100644 index 000000000..16a85f7a2 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodbaseband.h @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_M17DEMODBASEBAND_H +#define INCLUDE_M17DEMODBASEBAND_H + +#include +#include + +#include "dsp/samplesinkfifo.h" +#include "util/message.h" +#include "util/messagequeue.h" + +#include "m17demodsink.h" + +class DownChannelizer; +class ChannelAPI; + +class M17DemodBaseband : public QObject +{ + Q_OBJECT +public: + class MsgConfigureM17DemodBaseband : public Message { + MESSAGE_CLASS_DECLARATION + + public: + const M17DemodSettings& getSettings() const { return m_settings; } + bool getForce() const { return m_force; } + + static MsgConfigureM17DemodBaseband* create(const M17DemodSettings& settings, bool force) + { + return new MsgConfigureM17DemodBaseband(settings, force); + } + + private: + M17DemodSettings m_settings; + bool m_force; + + MsgConfigureM17DemodBaseband(const M17DemodSettings& settings, bool force) : + Message(), + m_settings(settings), + m_force(force) + { } + }; + + M17DemodBaseband(); + ~M17DemodBaseband(); + void reset(); + void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); + MessageQueue *getInputMessageQueue() { return &m_inputMessageQueue; } //!< Get the queue for asynchronous inbound communication + int getChannelSampleRate() const; + int getAudioSampleRate() const { return m_sink.getAudioSampleRate(); } + double getMagSq() { return m_sink.getMagSq(); } + void getMagSqLevels(double& avg, double& peak, int& nbSamples) { m_sink.getMagSqLevels(avg, peak, nbSamples); } + bool getSquelchOpen() const { return m_sink.getSquelchOpen(); } + void setBasebandSampleRate(int sampleRate); + void setScopeXYSink(BasebandSampleSink* scopeSink) { m_sink.setScopeXYSink(scopeSink); } + void configureMyPosition(float myLatitude, float myLongitude) { m_sink.configureMyPosition(myLatitude, myLongitude); } + void setChannel(ChannelAPI *channel); + void setFifoLabel(const QString& label) { m_sampleFifo.setLabel(label); } + void setAudioFifoLabel(const QString& label) { m_sink.setAudioFifoLabel(label); } + +private: + SampleSinkFifo m_sampleFifo; + DownChannelizer *m_channelizer; + int m_channelSampleRate; + M17DemodSink m_sink; + MessageQueue m_inputMessageQueue; //!< Queue for asynchronous inbound communication + M17DemodSettings m_settings; + QMutex m_mutex; + + bool handleMessage(const Message& cmd); + void applySettings(const M17DemodSettings& settings, bool force = false); + +private slots: + void handleInputMessages(); + void handleData(); //!< Handle data when samples have to be processed +}; + +#endif // INCLUDE_M17DEMODBASEBAND_H diff --git a/plugins/channelrx/demodm17/m17demodbaudrates.cpp b/plugins/channelrx/demodm17/m17demodbaudrates.cpp new file mode 100644 index 000000000..c7f4ccaad --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodbaudrates.cpp @@ -0,0 +1,48 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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 "m17demodbaudrates.h" + +unsigned int M17DemodBaudRates::m_rates[] = {4800}; +unsigned int M17DemodBaudRates::m_nb_rates = 1; +unsigned int M17DemodBaudRates::m_defaultRateIndex = 0; // 4800 bauds + +unsigned int M17DemodBaudRates::getRate(unsigned int rate_index) +{ + if (rate_index < m_nb_rates) + { + return m_rates[rate_index]; + } + else + { + return m_rates[m_defaultRateIndex]; + } +} + +unsigned int M17DemodBaudRates::getRateIndex(unsigned int rate) +{ + for (unsigned int i=0; i < m_nb_rates; i++) + { + if (rate == m_rates[i]) + { + return i; + } + } + + return m_defaultRateIndex; +} diff --git a/plugins/channelrx/demodm17/m17demodbaudrates.h b/plugins/channelrx/demodm17/m17demodbaudrates.h new file mode 100644 index 000000000..61efae1cb --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodbaudrates.h @@ -0,0 +1,36 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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_CHANNELRX_DEMODM17_M17DEMODBAUDRATES_H_ +#define PLUGINS_CHANNELRX_DEMODM17_M17DEMODBAUDRATES_H_ + +class M17DemodBaudRates +{ +public: + static unsigned int getRate(unsigned int rate_index); + static unsigned int getRateIndex(unsigned int rate); + static unsigned int getDefaultRate() { return m_rates[m_defaultRateIndex]; } + static unsigned int getDefaultRateIndex() { return m_defaultRateIndex; } + static unsigned int getNbRates() { return m_nb_rates; } +private: + static unsigned int m_nb_rates; + static unsigned int m_rates[2]; + static unsigned int m_defaultRateIndex; +}; + +#endif /* PLUGINS_CHANNELRX_DEMODM17_M17DEMODBAUDRATES_H_ */ diff --git a/plugins/channelrx/demodm17/m17demodgui.cpp b/plugins/channelrx/demodm17/m17demodgui.cpp new file mode 100644 index 000000000..01c45873f --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodgui.cpp @@ -0,0 +1,571 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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 "device/deviceuiset.h" +#include "dsp/scopevisxy.h" +#include "dsp/dspcommands.h" +#include "plugin/pluginapi.h" +#include "util/simpleserializer.h" +#include "util/db.h" +#include "gui/basicchannelsettingsdialog.h" +#include "gui/devicestreamselectiondialog.h" +#include "gui/crightclickenabler.h" +#include "gui/audioselectdialog.h" +#include "dsp/dspengine.h" +#include "maincore.h" + +#include "m17demod.h" +#include "m17demodbaudrates.h" +#include "ui_m17demodgui.h" +#include "m17demodgui.h" + + +M17DemodGUI* M17DemodGUI::create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) +{ + M17DemodGUI* gui = new M17DemodGUI(pluginAPI, deviceUISet, rxChannel); + return gui; +} + +void M17DemodGUI::destroy() +{ + delete this; +} + +void M17DemodGUI::resetToDefaults() +{ + m_settings.resetToDefaults(); + blockApplySettings(true); + displaySettings(); + blockApplySettings(false); + applySettings(); +} + +QByteArray M17DemodGUI::serialize() const +{ + return m_settings.serialize(); +} + +bool M17DemodGUI::deserialize(const QByteArray& data) +{ + if (m_settings.deserialize(data)) + { + displaySettings(); + applySettings(true); + return true; + } + else + { + resetToDefaults(); + return false; + } +} + +void M17DemodGUI::resizeEvent(QResizeEvent* size) +{ + int maxWidth = getRollupContents()->maximumWidth(); + int minHeight = getRollupContents()->minimumHeight() + getAdditionalHeight(); + resize(width() < maxWidth ? width() : maxWidth, minHeight); + size->accept(); +} + +bool M17DemodGUI::handleMessage(const Message& message) +{ + if (M17Demod::MsgConfigureM17Demod::match(message)) + { + qDebug("M17DemodGUI::handleMessage: M17Demod::MsgConfigureM17Demod"); + const M17Demod::MsgConfigureM17Demod& cfg = (M17Demod::MsgConfigureM17Demod&) message; + m_settings = cfg.getSettings(); + blockApplySettings(true); + m_channelMarker.updateSettings(static_cast(m_settings.m_channelMarker)); + displaySettings(); + blockApplySettings(false); + return true; + } + else if (DSPSignalNotification::match(message)) + { + DSPSignalNotification& notif = (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 M17DemodGUI::handleInputMessages() +{ + Message* message; + + while ((message = getInputMessageQueue()->pop()) != 0) + { + if (handleMessage(*message)) + { + delete message; + } + } +} + +void M17DemodGUI::on_deltaFrequency_changed(qint64 value) +{ + m_channelMarker.setCenterFrequency(value); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + updateAbsoluteCenterFrequency(); + applySettings(); +} + +void M17DemodGUI::on_rfBW_valueChanged(int value) +{ + m_channelMarker.setBandwidth(value * 100); + m_settings.m_rfBandwidth = value * 100.0; + ui->rfBWText->setText(QString("%1k").arg(value / 10.0, 0, 'f', 1)); + applySettings(); +} + +void M17DemodGUI::on_demodGain_valueChanged(int value) +{ + m_settings.m_demodGain = value / 100.0; + ui->demodGainText->setText(QString("%1").arg(value / 100.0, 0, 'f', 2)); + applySettings(); +} + +void M17DemodGUI::on_fmDeviation_valueChanged(int value) +{ + m_settings.m_fmDeviation = value * 100.0; + ui->fmDeviationText->setText(QString("%1%2k").arg(QChar(0xB1, 0x00)).arg(value / 10.0, 0, 'f', 1)); + applySettings(); +} + +void M17DemodGUI::on_volume_valueChanged(int value) +{ + m_settings.m_volume= value / 10.0; + ui->volumeText->setText(QString("%1").arg(value / 10.0, 0, 'f', 1)); + applySettings(); +} + +void M17DemodGUI::on_baudRate_currentIndexChanged(int index) +{ + m_settings.m_baudRate = M17DemodBaudRates::getRate(index); + applySettings(); +} + +void M17DemodGUI::on_syncOrConstellation_toggled(bool checked) +{ + m_settings.m_syncOrConstellation = checked; + applySettings(); +} + +void M17DemodGUI::on_traceLength_valueChanged(int value) +{ + m_settings.m_traceLengthMutliplier = value; + ui->traceLengthText->setText(QString("%1").arg(m_settings.m_traceLengthMutliplier*50)); + m_scopeVisXY->setPixelsPerFrame(m_settings.m_traceLengthMutliplier*960); // 48000 / 50. Chunks of 50 ms. +} + +void M17DemodGUI::on_traceStroke_valueChanged(int value) +{ + m_settings.m_traceStroke = value; + ui->traceStrokeText->setText(QString("%1").arg(m_settings.m_traceStroke)); + m_scopeVisXY->setStroke(m_settings.m_traceStroke); +} + +void M17DemodGUI::on_traceDecay_valueChanged(int value) +{ + m_settings.m_traceDecay = value; + ui->traceDecayText->setText(QString("%1").arg(m_settings.m_traceDecay)); + m_scopeVisXY->setDecay(m_settings.m_traceDecay); +} + +void M17DemodGUI::on_squelchGate_valueChanged(int value) +{ + m_settings.m_squelchGate = value; + ui->squelchGateText->setText(QString("%1").arg(value * 10.0, 0, 'f', 0)); + applySettings(); +} + +void M17DemodGUI::on_squelch_valueChanged(int value) +{ + ui->squelchText->setText(QString("%1").arg(value / 1.0, 0, 'f', 0)); + m_settings.m_squelch = value; + applySettings(); +} + +void M17DemodGUI::on_audioMute_toggled(bool checked) +{ + m_settings.m_audioMute = checked; + applySettings(); +} + +void M17DemodGUI::on_highPassFilter_toggled(bool checked) +{ + m_settings.m_highPassFilter = checked; + applySettings(); +} + +void M17DemodGUI::onWidgetRolled(QWidget* widget, bool rollDown) +{ + (void) widget; + (void) rollDown; + + getRollupContents()->saveState(m_rollupState); + applySettings(); +} + +void M17DemodGUI::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_m17Demod->getNumberOfDeviceStreams()); + dialog.setStreamIndex(m_settings.m_streamIndex); + } + + dialog.move(p); + 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(); +} + +void M17DemodGUI::on_viewStatusLog_clicked() +{ + qDebug("M17DemodGUI::on_viewStatusLog_clicked"); + m_m17StatusTextDialog.exec(); +} + +M17DemodGUI::M17DemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent) : + ChannelGUI(parent), + ui(new Ui::M17DemodGUI), + m_pluginAPI(pluginAPI), + m_deviceUISet(deviceUISet), + m_channelMarker(this), + m_deviceCenterFrequency(0), + m_basebandSampleRate(1), + m_doApplySettings(true), + m_enableCosineFiltering(false), + m_syncOrConstellation(false), + m_slot1On(false), + m_slot2On(false), + m_tdmaStereo(false), + m_squelchOpen(false), + m_audioSampleRate(-1), + m_tickCount(0) +{ + setAttribute(Qt::WA_DeleteOnClose, true); + m_helpURL = "plugins/channelrx/demodm17/readme.md"; + RollupContents *rollupContents = getRollupContents(); + ui->setupUi(rollupContents); + setSizePolicy(rollupContents->sizePolicy()); + rollupContents->arrangeRollups(); + connect(rollupContents, SIGNAL(widgetRolled(QWidget*,bool)), this, SLOT(onWidgetRolled(QWidget*,bool))); + + ui->screenTV->setColor(true); + ui->screenTV->resizeTVScreen(200,200); + + connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onMenuDialogCalled(const QPoint &))); + connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); + + CRightClickEnabler *audioMuteRightClickEnabler = new CRightClickEnabler(ui->audioMute); + connect(audioMuteRightClickEnabler, SIGNAL(rightClick(const QPoint &)), this, SLOT(audioSelect())); + + m_scopeVisXY = new ScopeVisXY(ui->screenTV); + m_scopeVisXY->setScale(2.0); + m_scopeVisXY->setPixelsPerFrame(4001); + m_scopeVisXY->setPlotRGB(qRgb(0, 220, 250)); + m_scopeVisXY->setGridRGB(qRgb(255, 255, 128)); + + for (float x = -0.84; x < 1.0; x += 0.56) + { + for (float y = -0.84; y < 1.0; y += 0.56) + { + m_scopeVisXY->addGraticulePoint(std::complex(x, y)); + } + } + + m_scopeVisXY->calculateGraticule(200,200); + + m_m17Demod = (M17Demod*) rxChannel; + m_m17Demod->setScopeXYSink(m_scopeVisXY); + m_m17Demod->setMessageQueueToGUI(getInputMessageQueue()); + + connect(&MainCore::instance()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); + + ui->audioMute->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + + ui->deltaFrequencyLabel->setText(QString("%1f").arg(QChar(0x94, 0x03))); + ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); + ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); + ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenAndBlue); + + m_channelMarker.blockSignals(true); + m_channelMarker.setColor(Qt::cyan); + m_channelMarker.setBandwidth(10000); + m_channelMarker.setCenterFrequency(0); + m_channelMarker.setTitle("M17 Demodulator"); + 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(&m_channelMarker, SIGNAL(highlightedByCursor()), this, SLOT(channelMarkerHighlightedByCursor())); + + m_settings.setChannelMarker(&m_channelMarker); + m_settings.setRollupState(&m_rollupState); + + updateMyPosition(); + displaySettings(); + makeUIConnections(); + applySettings(true); +} + +M17DemodGUI::~M17DemodGUI() +{ + delete m_scopeVisXY; + ui->screenTV->setParent(nullptr); // Prefer memory leak to core dump... ~TVScreen() is buggy + delete ui; +} + +void M17DemodGUI::updateMyPosition() +{ + float latitude = MainCore::instance()->getSettings().getLatitude(); + float longitude = MainCore::instance()->getSettings().getLongitude(); + + if ((m_myLatitude != latitude) || (m_myLongitude != longitude)) + { + m_m17Demod->configureMyPosition(latitude, longitude); + m_myLatitude = latitude; + m_myLongitude = longitude; + } +} + +void M17DemodGUI::displaySettings() +{ + m_channelMarker.blockSignals(true); + m_channelMarker.setCenterFrequency(m_settings.m_inputFrequencyOffset); + m_channelMarker.setColor(m_settings.m_rgbColor); + m_channelMarker.setTitle(m_settings.m_title); + m_channelMarker.blockSignals(false); + setTitleColor(m_settings.m_rgbColor); // activate signal on the last setting only + + setTitleColor(m_settings.m_rgbColor); + setWindowTitle(m_channelMarker.getTitle()); + setTitle(m_channelMarker.getTitle()); + + blockApplySettings(true); + + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + + ui->rfBW->setValue(m_settings.m_rfBandwidth / 100.0); + ui->rfBWText->setText(QString("%1k").arg(ui->rfBW->value() / 10.0, 0, 'f', 1)); + + ui->fmDeviation->setValue(m_settings.m_fmDeviation / 100.0); + ui->fmDeviationText->setText(QString("%1%2k").arg(QChar(0xB1, 0x00)).arg(ui->fmDeviation->value() / 10.0, 0, 'f', 1)); + + ui->squelch->setValue(m_settings.m_squelch); + ui->squelchText->setText(QString("%1").arg(ui->squelch->value() / 1.0, 0, 'f', 0)); + + ui->squelchGate->setValue(m_settings.m_squelchGate); + ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0)); + + ui->demodGain->setValue(m_settings.m_demodGain * 100.0); + ui->demodGainText->setText(QString("%1").arg(ui->demodGain->value() / 100.0, 0, 'f', 2)); + + ui->volume->setValue(m_settings.m_volume * 10.0); + ui->volumeText->setText(QString("%1").arg(ui->volume->value() / 10.0, 0, 'f', 1)); + + ui->syncOrConstellation->setChecked(m_settings.m_syncOrConstellation); + ui->audioMute->setChecked(m_settings.m_audioMute); + ui->highPassFilter->setChecked(m_settings.m_highPassFilter); + + ui->baudRate->setCurrentIndex(M17DemodBaudRates::getRateIndex(m_settings.m_baudRate)); + + ui->traceLength->setValue(m_settings.m_traceLengthMutliplier); + ui->traceLengthText->setText(QString("%1").arg(m_settings.m_traceLengthMutliplier*50)); + m_scopeVisXY->setPixelsPerFrame(m_settings.m_traceLengthMutliplier*960); // 48000 / 50. Chunks of 50 ms. + + ui->traceStroke->setValue(m_settings.m_traceStroke); + ui->traceStrokeText->setText(QString("%1").arg(m_settings.m_traceStroke)); + m_scopeVisXY->setStroke(m_settings.m_traceStroke); + + ui->traceDecay->setValue(m_settings.m_traceDecay); + ui->traceDecayText->setText(QString("%1").arg(m_settings.m_traceDecay)); + m_scopeVisXY->setDecay(m_settings.m_traceDecay); + + updateIndexLabel(); + + getRollupContents()->restoreState(m_rollupState); + updateAbsoluteCenterFrequency(); + blockApplySettings(false); +} + +void M17DemodGUI::applySettings(bool force) +{ + if (m_doApplySettings) + { + qDebug() << "M17DemodGUI::applySettings"; + + M17Demod::MsgConfigureM17Demod* message = M17Demod::MsgConfigureM17Demod::create( m_settings, force); + m_m17Demod->getInputMessageQueue()->push(message); + } +} + +void M17DemodGUI::leaveEvent(QEvent* event) +{ + m_channelMarker.setHighlighted(false); + ChannelGUI::leaveEvent(event); +} + +void M17DemodGUI::enterEvent(QEvent* event) +{ + m_channelMarker.setHighlighted(true); + ChannelGUI::enterEvent(event); +} + +void M17DemodGUI::blockApplySettings(bool block) +{ + m_doApplySettings = !block; +} + +void M17DemodGUI::channelMarkerChangedByCursor() +{ + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); + m_settings.m_inputFrequencyOffset = m_channelMarker.getCenterFrequency(); + applySettings(); +} + +void M17DemodGUI::channelMarkerHighlightedByCursor() +{ + setHighlighted(m_channelMarker.getHighlighted()); +} + +void M17DemodGUI::audioSelect() +{ + qDebug("M17DemodGUI::audioSelect"); + AudioSelectDialog audioSelect(DSPEngine::instance()->getAudioDeviceManager(), m_settings.m_audioDeviceName); + audioSelect.exec(); + + if (audioSelect.m_selected) + { + m_settings.m_audioDeviceName = audioSelect.m_audioDeviceName; + applySettings(); + } +} + +void M17DemodGUI::tick() +{ + double magsqAvg, magsqPeak; + int nbMagsqSamples; + m_m17Demod->getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples); + double powDbAvg = CalcDb::dbPower(magsqAvg); + double powDbPeak = CalcDb::dbPower(magsqPeak); + + ui->channelPowerMeter->levelChanged( + (100.0f + powDbAvg) / 100.0f, + (100.0f + powDbPeak) / 100.0f, + nbMagsqSamples); + + if (m_tickCount % 4 == 0) { + ui->channelPower->setText(tr("%1 dB").arg(powDbAvg, 0, 'f', 1)); + } + + int audioSampleRate = m_m17Demod->getAudioSampleRate(); + bool squelchOpen = m_m17Demod->getSquelchOpen(); + + if ((audioSampleRate != m_audioSampleRate) || (squelchOpen != m_squelchOpen)) + { + if (audioSampleRate < 0) { + ui->audioMute->setStyleSheet("QToolButton { background-color : red; }"); + } else if (squelchOpen) { + ui->audioMute->setStyleSheet("QToolButton { background-color : green; }"); + } else { + ui->audioMute->setStyleSheet("QToolButton { background:rgb(79,79,79); }"); + } + + m_audioSampleRate = audioSampleRate; + m_squelchOpen = squelchOpen; + } + + m_tickCount++; +} + +void M17DemodGUI::makeUIConnections() +{ + QObject::connect(ui->deltaFrequency, &ValueDialZ::changed, this, &M17DemodGUI::on_deltaFrequency_changed); + QObject::connect(ui->rfBW, &QSlider::valueChanged, this, &M17DemodGUI::on_rfBW_valueChanged); + QObject::connect(ui->demodGain, &QSlider::valueChanged, this, &M17DemodGUI::on_demodGain_valueChanged); + QObject::connect(ui->volume, &QDial::valueChanged, this, &M17DemodGUI::on_volume_valueChanged); + QObject::connect(ui->baudRate, QOverload::of(&QComboBox::currentIndexChanged), this, &M17DemodGUI::on_baudRate_currentIndexChanged); + QObject::connect(ui->syncOrConstellation, &QToolButton::toggled, this, &M17DemodGUI::on_syncOrConstellation_toggled); + QObject::connect(ui->traceLength, &QDial::valueChanged, this, &M17DemodGUI::on_traceLength_valueChanged); + QObject::connect(ui->traceStroke, &QDial::valueChanged, this, &M17DemodGUI::on_traceStroke_valueChanged); + QObject::connect(ui->traceDecay, &QDial::valueChanged, this, &M17DemodGUI::on_traceDecay_valueChanged); + QObject::connect(ui->fmDeviation, &QSlider::valueChanged, this, &M17DemodGUI::on_fmDeviation_valueChanged); + QObject::connect(ui->squelchGate, &QDial::valueChanged, this, &M17DemodGUI::on_squelchGate_valueChanged); + QObject::connect(ui->squelch, &QDial::valueChanged, this, &M17DemodGUI::on_squelch_valueChanged); + QObject::connect(ui->highPassFilter, &ButtonSwitch::toggled, this, &M17DemodGUI::on_highPassFilter_toggled); + QObject::connect(ui->audioMute, &QToolButton::toggled, this, &M17DemodGUI::on_audioMute_toggled); + QObject::connect(ui->viewStatusLog, &QPushButton::clicked, this, &M17DemodGUI::on_viewStatusLog_clicked); +} + +void M17DemodGUI::updateAbsoluteCenterFrequency() +{ + setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); +} diff --git a/plugins/channelrx/demodm17/m17demodgui.h b/plugins/channelrx/demodm17/m17demodgui.h new file mode 100644 index 000000000..24973446e --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodgui.h @@ -0,0 +1,142 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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_M17DEMODGUI_H +#define INCLUDE_M17DEMODGUI_H + +#include + +#include "channel/channelgui.h" +#include "dsp/dsptypes.h" +#include "dsp/channelmarker.h" +#include "dsp/movingaverage.h" +#include "util/messagequeue.h" +#include "settings/rollupstate.h" + +#include "m17demodsettings.h" +#include "m17statustextdialog.h" + +class PluginAPI; +class DeviceUISet; +class BasebandSampleSink; +class ScopeVisXY; +class M17Demod; + +namespace Ui { + class M17DemodGUI; +} + +class M17DemodGUI : public ChannelGUI { + Q_OBJECT + +public: + static M17DemodGUI* create(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel); + 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(); + void channelMarkerHighlightedByCursor(); + +protected: + void resizeEvent(QResizeEvent* size); + +private: + Ui::M17DemodGUI* ui; + PluginAPI* m_pluginAPI; + DeviceUISet* m_deviceUISet; + ChannelMarker m_channelMarker; + RollupState m_rollupState; + M17DemodSettings m_settings; + qint64 m_deviceCenterFrequency; + int m_basebandSampleRate; + bool m_doApplySettings; + + ScopeVisXY* m_scopeVisXY; + + M17Demod* m_m17Demod; + bool m_enableCosineFiltering; + bool m_syncOrConstellation; + bool m_slot1On; + bool m_slot2On; + bool m_tdmaStereo; + bool m_audioMute; + bool m_squelchOpen; + int m_audioSampleRate; + uint32_t m_tickCount; + + float m_myLatitude; + float m_myLongitude; + + MessageQueue m_inputMessageQueue; + M17StatusTextDialog m_m17StatusTextDialog; + + explicit M17DemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel, QWidget* parent = nullptr); + virtual ~M17DemodGUI(); + + void blockApplySettings(bool block); + void applySettings(bool force = false); + void displaySettings(); + void updateAMBEFeaturesList(); + void updateMyPosition(); + bool handleMessage(const Message& message); + void makeUIConnections(); + void updateAbsoluteCenterFrequency(); + + void leaveEvent(QEvent*); + void enterEvent(QEvent*); + +private slots: + void on_deltaFrequency_changed(qint64 value); + void on_rfBW_valueChanged(int index); + void on_demodGain_valueChanged(int value); + void on_volume_valueChanged(int value); + void on_baudRate_currentIndexChanged(int index); + void on_syncOrConstellation_toggled(bool checked); + void on_traceLength_valueChanged(int value); + void on_traceStroke_valueChanged(int value); + void on_traceDecay_valueChanged(int value); + void on_fmDeviation_valueChanged(int value); + void on_squelchGate_valueChanged(int value); + void on_squelch_valueChanged(int value); + void on_highPassFilter_toggled(bool checked); + void on_audioMute_toggled(bool checked); + void onWidgetRolled(QWidget* widget, bool rollDown); + void onMenuDialogCalled(const QPoint& p); + void on_viewStatusLog_clicked(); + void handleInputMessages(); + void audioSelect(); + void tick(); +}; + +#endif // INCLUDE_DSDDEMODGUI_H diff --git a/plugins/channelrx/demodm17/m17demodgui.ui b/plugins/channelrx/demodm17/m17demodgui.ui new file mode 100644 index 000000000..8749f11c4 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodgui.ui @@ -0,0 +1,1169 @@ + + + M17DemodGUI + + + + 0 + 0 + 530 + 392 + + + + + 0 + 0 + + + + + 530 + 392 + + + + + 750 + 392 + + + + + Liberation Sans + 9 + + + + M17 Demodulator + + + + + 0 + 0 + 528 + 172 + + + + + 0 + 0 + + + + + 528 + 0 + + + + Settings + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + 2 + + + + + 6 + + + + + + 16 + 0 + + + + Df + + + + + + + + 0 + 0 + + + + + 32 + 16 + + + + + Liberation Mono + 12 + + + + PointingHandCursor + + + Qt::StrongFocus + + + Demod shift frequency from center in Hz + + + + + + + Hz + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + RFBW + + + + + + + Bandwidth (kHz) before discriminator + + + 500 + + + 1 + + + 100 + + + Qt::Horizontal + + + + + + + + 40 + 0 + + + + 00.0k + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 60 + 0 + + + + Channel power (dB) + + + Qt::RightToLeft + + + -100.0 dB + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + Level meter (dB) top trace: average, bottom trace: instantaneous peak, tip: peak hold + + + dB + + + + + + + + 0 + 0 + + + + + 0 + 24 + + + + + Liberation Mono + 8 + + + + + + + + + + + + Activate status text log + + + + + + + + + + + 24 + 0 + + + + + 24 + 16777215 + + + + View status text log + + + + + + + :/listing.png:/listing.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Vertical + + + + + + + Vol + + + + + + + + 24 + 24 + + + + Sound volume + + + 100 + + + 1 + + + 20 + + + + + + + + 30 + 0 + + + + + 30 + 16777215 + + + + Sound volume + + + 10.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Vertical + + + + + + + Sq + + + + + + + + 24 + 24 + + + + Squelch threshold (dB) + + + -100 + + + 0 + + + 1 + + + 1 + + + -40 + + + + + + + + 30 + 0 + + + + Squelch threshold (dB) + + + -100 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 24 + 24 + + + + Squelch gate (ms) + + + 0 + + + 50 + + + 1 + + + 5 + + + 5 + + + + + + + + 25 + 0 + + + + Squelch gate (ms) + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Toggle audio high pass filter + + + + + + + :/filter_highpass.png:/filter_highpass.png + + + + + + + Left: Mute/Unmute audio (all slots) Right: select audio output + + + ... + + + + :/sound_on.png + :/sound_off.png:/sound_on.png + + + true + + + + + + + + + 2 + + + 2 + + + 2 + + + + + Source + + + + + + + + 80 + 0 + + + + ... + + + + + + + Dest + + + + + + + + 80 + 0 + + + + ... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + 10 + 180 + 480 + 210 + + + + + 480 + 210 + + + + Digital + + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + 200 + 200 + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 59 + 20 + + + + + 0 + 0 + + + + + 35 + 0 + + + + + 16777215 + 16777215 + + + + Baud rate: 2.4k: NXDN48, dPMR 4.8k: DMR, D-Star, YSF, NXDN96 + + + + 4.8k + + + + + + + 80 + 10 + 110 + 25 + + + + + 110 + 0 + + + + + 16777215 + 25 + + + + + Liberation Mono + 9 + + + + Synchronized on this frame type + + + QFrame::Box + + + QFrame::Sunken + + + 2 + + + No Sync______ + + + + + + 10 + 40 + 25 + 28 + + + + + 25 + 0 + + + + Symbol synchronization rate (%) + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 40 + 40 + 25 + 28 + + + + + 25 + 0 + + + + Zero crossing relative position in number of samples (<0 sampling point lags, >0 it leads) + + + -00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 80 + 40 + 25 + 28 + + + + + 25 + 0 + + + + Carrier relative position (%) when synchronized + + + -00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 110 + 40 + 25 + 28 + + + + + 25 + 0 + + + + Carrier input level (%) when synchronized + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 70 + 23 + 22 + + + + Toggle between transition constellation and symbol synchronization displays + + + + + + + :/constellation.png + :/slopep_icon.png:/constellation.png + + + true + + + + + + 50 + 107 + 141 + 16 + + + + Maximum frequency deviation (kHz) + + + 100 + + + 1 + + + 35 + + + 35 + + + Qt::Horizontal + + + + + + 10 + 100 + 25 + 29 + + + + FMd + + + + + + 200 + 100 + 50 + 29 + + + + + 50 + 0 + + + + +00.0k + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 10 + 130 + 28 + 30 + + + + Gain + + + + + + 50 + 137 + 141 + 16 + + + + + 0 + 0 + + + + Gain after discriminator + + + 50 + + + 200 + + + 1 + + + 100 + + + Qt::Horizontal + + + + + + 40 + 68 + 24 + 24 + + + + + 24 + 24 + + + + Display trace length (ms) + + + 6 + + + 30 + + + 1 + + + 6 + + + + + + 70 + 73 + 31 + 16 + + + + Display trace length (ms) + + + 0000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 200 + 130 + 50 + 29 + + + + + 50 + 0 + + + + 0.00 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 110 + 70 + 24 + 24 + + + + + 24 + 24 + + + + Trace stroke [0..255] + + + 0 + + + 255 + + + 1 + + + 100 + + + + + + 130 + 73 + 31 + 16 + + + + Trace stroke value + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 170 + 70 + 24 + 24 + + + + + 24 + 24 + + + + Trace decay [0..255] + + + 0 + + + 255 + + + 1 + + + 200 + + + + + + 190 + 73 + 31 + 16 + + + + Trace decay value + + + 000 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + RollupContents + QWidget +
gui/rollupcontents.h
+ 1 +
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
+ + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+ + LevelMeterSignalDB + QWidget +
gui/levelmeter.h
+ 1 +
+ + TVScreen + QWidget +
gui/tvscreen.h
+ 1 +
+
+ + + + +
diff --git a/plugins/channelrx/demodm17/m17demodplugin.cpp b/plugins/channelrx/demodm17/m17demodplugin.cpp new file mode 100644 index 000000000..78e4a8e18 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodplugin.cpp @@ -0,0 +1,94 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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 "m17demodplugin.h" + +#include +#include "plugin/pluginapi.h" +#ifndef SERVER_MODE +#include "m17demodgui.h" +#endif +#include "m17demod.h" +#include "m17demodwebapiadapter.h" +#include "m17demodplugin.h" + +const PluginDescriptor M17DemodPlugin::m_pluginDescriptor = { + M17Demod::m_channelId, + QStringLiteral("M17 Demodulator"), + QStringLiteral("7.4.0"), + QStringLiteral("(c) Edouard Griffiths, F4EXB"), + QStringLiteral("https://github.com/f4exb/sdrangel"), + true, + QStringLiteral("https://github.com/f4exb/sdrangel") +}; + +M17DemodPlugin::M17DemodPlugin(QObject* parent) : + QObject(parent), + m_pluginAPI(nullptr) +{ +} + +const PluginDescriptor& M17DemodPlugin::getPluginDescriptor() const +{ + return m_pluginDescriptor; +} + +void M17DemodPlugin::initPlugin(PluginAPI* pluginAPI) +{ + m_pluginAPI = pluginAPI; + + // register DSD demodulator + m_pluginAPI->registerRxChannel(M17Demod::m_channelIdURI, M17Demod::m_channelId, this); +} + +void M17DemodPlugin::createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const +{ + if (bs || cs) + { + M17Demod *instance = new M17Demod(deviceAPI); + + if (bs) { + *bs = instance; + } + + if (cs) { + *cs = instance; + } + } +} + +#ifdef SERVER_MODE +ChannelGUI* M17DemodPlugin::createRxChannelGUI( + DeviceUISet *deviceUISet, + BasebandSampleSink *rxChannel) const +{ + (void) deviceUISet; + (void) rxChannel; + return nullptr; +} +#else +ChannelGUI* M17DemodPlugin::createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const +{ + return M17DemodGUI::create(m_pluginAPI, deviceUISet, rxChannel); +} +#endif + +ChannelWebAPIAdapter* M17DemodPlugin::createChannelWebAPIAdapter() const +{ + return new M17DemodWebAPIAdapter(); +} diff --git a/plugins/channelrx/demodm17/m17demodplugin.h b/plugins/channelrx/demodm17/m17demodplugin.h new file mode 100644 index 000000000..dce0c642d --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodplugin.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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_M17DEMODLUGIN_H +#define INCLUDE_M17DEMODLUGIN_H + +#include +#include "plugin/plugininterface.h" + +class DeviceUISet; +class BasebandSampleSink; + +class M17DemodPlugin : public QObject, PluginInterface { + Q_OBJECT + Q_INTERFACES(PluginInterface) + Q_PLUGIN_METADATA(IID "sdrangel.channel.m17demod") + +public: + explicit M17DemodPlugin(QObject* parent = nullptr); + + const PluginDescriptor& getPluginDescriptor() const; + void initPlugin(PluginAPI* pluginAPI); + + virtual void createRxChannel(DeviceAPI *deviceAPI, BasebandSampleSink **bs, ChannelAPI **cs) const; + virtual ChannelGUI* createRxChannelGUI(DeviceUISet *deviceUISet, BasebandSampleSink *rxChannel) const; + virtual ChannelWebAPIAdapter* createChannelWebAPIAdapter() const; + +private: + static const PluginDescriptor m_pluginDescriptor; + + PluginAPI* m_pluginAPI; +}; + +#endif // INCLUDE_M17DEMODLUGIN_H diff --git a/plugins/channelrx/demodm17/m17demodsettings.cpp b/plugins/channelrx/demodm17/m17demodsettings.cpp new file mode 100644 index 000000000..2fc653a27 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodsettings.cpp @@ -0,0 +1,188 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 Edouard Griffiths, F4EXB. // +// // +// This program is free som_udpCopyAudioftware; 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/dspengine.h" +#include "util/simpleserializer.h" +#include "settings/serializable.h" + +#include "m17demodsettings.h" + +M17DemodSettings::M17DemodSettings() : + m_channelMarker(nullptr), + m_rollupState(nullptr) +{ + resetToDefaults(); +} + +void M17DemodSettings::resetToDefaults() +{ + m_inputFrequencyOffset = 0; + m_rfBandwidth = 12500.0; + m_fmDeviation = 3500.0; + m_demodGain = 1.0; + m_volume = 2.0; + m_baudRate = 4800; + m_squelchGate = 5; // 10s of ms at 48000 Hz sample rate. Corresponds to 2400 for AGC attack + m_squelch = -40.0; + m_audioMute = false; + m_syncOrConstellation = false; + m_rgbColor = QColor(255, 0, 255).rgb(); + m_title = "M17 Demodulator"; + m_highPassFilter = false; + m_traceLengthMutliplier = 6; // 300 ms + m_traceStroke = 100; + m_traceDecay = 200; + m_audioDeviceName = AudioDeviceManager::m_defaultDeviceName; + m_streamIndex = 0; + m_useReverseAPI = false; + m_reverseAPIAddress = "127.0.0.1"; + m_reverseAPIPort = 8888; + m_reverseAPIDeviceIndex = 0; + m_reverseAPIChannelIndex = 0; + m_workspaceIndex = 0; + m_hidden = false; +} + +QByteArray M17DemodSettings::serialize() const +{ + SimpleSerializer s(1); + s.writeS32(1, m_inputFrequencyOffset); + s.writeS32(2, m_rfBandwidth/100.0); + s.writeS32(3, m_demodGain*100.0); + s.writeS32(4, m_fmDeviation/100.0); + s.writeS32(5, m_squelch); + s.writeU32(7, m_rgbColor); + s.writeS32(8, m_squelchGate); + s.writeS32(9, m_volume*10.0); + s.writeS32(11, m_baudRate); + s.writeBool(13, m_syncOrConstellation); + + if (m_channelMarker) { + s.writeBlob(17, m_channelMarker->serialize()); + } + + s.writeString(18, m_title); + s.writeBool(19, m_highPassFilter); + s.writeString(20, m_audioDeviceName); + s.writeS32(21, m_traceLengthMutliplier); + s.writeS32(22, m_traceStroke); + s.writeS32(23, m_traceDecay); + s.writeBool(24, m_useReverseAPI); + s.writeString(25, m_reverseAPIAddress); + s.writeU32(26, m_reverseAPIPort); + s.writeU32(27, m_reverseAPIDeviceIndex); + s.writeU32(28, m_reverseAPIChannelIndex); + s.writeBool(29, m_audioMute); + s.writeS32(30, m_streamIndex); + + if (m_rollupState) { + s.writeBlob(31, m_rollupState->serialize()); + } + + s.writeS32(32, m_workspaceIndex); + s.writeBlob(33, m_geometryBytes); + s.writeBool(34, m_hidden); + + return s.final(); +} + +bool M17DemodSettings::deserialize(const QByteArray& data) +{ + SimpleDeserializer d(data); + + if (!d.isValid()) + { + resetToDefaults(); + return false; + } + + if (d.getVersion() == 1) + { + QByteArray bytetmp; + QString strtmp; + qint32 tmp; + uint32_t utmp; + + if (m_channelMarker) + { + d.readBlob(17, &bytetmp); + m_channelMarker->deserialize(bytetmp); + } + + d.readS32(1, &tmp, 0); + m_inputFrequencyOffset = tmp; + d.readS32(2, &tmp, 125); + m_rfBandwidth = tmp * 100.0; + d.readS32(3, &tmp, 125); + m_demodGain = tmp / 100.0; + d.readS32(4, &tmp, 50); + m_fmDeviation = tmp * 100.0; + d.readS32(5, &tmp, -40); + m_squelch = tmp < -100 ? tmp / 10.0 : tmp; + d.readU32(7, &m_rgbColor); + d.readS32(8, &m_squelchGate, 5); + d.readS32(9, &tmp, 20); + m_volume = tmp / 10.0; + d.readS32(11, &m_baudRate, 4800); + d.readBool(13, &m_syncOrConstellation, false); + d.readString(18, &m_title, "M17 Demodulator"); + d.readBool(19, &m_highPassFilter, false); + d.readString(20, &m_audioDeviceName, AudioDeviceManager::m_defaultDeviceName); + d.readS32(21, &tmp, 6); + m_traceLengthMutliplier = tmp < 2 ? 2 : tmp > 30 ? 30 : tmp; + d.readS32(22, &tmp, 100); + m_traceStroke = tmp < 0 ? 0 : tmp > 255 ? 255 : tmp; + d.readS32(23, &tmp, 200); + m_traceDecay = tmp < 0 ? 0 : tmp > 255 ? 255 : tmp; + d.readBool(24, &m_useReverseAPI, false); + d.readString(25, &m_reverseAPIAddress, "127.0.0.1"); + d.readU32(26, &utmp, 0); + + if ((utmp > 1023) && (utmp < 65535)) { + m_reverseAPIPort = utmp; + } else { + m_reverseAPIPort = 8888; + } + + d.readU32(27, &utmp, 0); + m_reverseAPIDeviceIndex = utmp > 99 ? 99 : utmp; + d.readU32(28, &utmp, 0); + m_reverseAPIChannelIndex = utmp > 99 ? 99 : utmp; + d.readBool(29, &m_audioMute, false); + d.readS32(30, &m_streamIndex, 0); + + if (m_rollupState) + { + d.readBlob(31, &bytetmp); + m_rollupState->deserialize(bytetmp); + } + + d.readS32(32, &m_workspaceIndex, 0); + d.readBlob(33, &m_geometryBytes); + d.readBool(34, &m_hidden, false); + + return true; + } + else + { + resetToDefaults(); + return false; + } +} + diff --git a/plugins/channelrx/demodm17/m17demodsettings.h b/plugins/channelrx/demodm17/m17demodsettings.h new file mode 100644 index 000000000..1ebd6e5b6 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodsettings.h @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 Edouard Griffiths, F4EXB. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef PLUGINS_CHANNELRX_DEMODM17_M17DEMODSETTINGS_H_ +#define PLUGINS_CHANNELRX_DEMODM17_M17DEMODSETTINGS_H_ + +#include +#include + +#include + +class Serializable; + +struct M17DemodSettings +{ + qint64 m_inputFrequencyOffset; + Real m_rfBandwidth; + Real m_fmDeviation; + Real m_demodGain; + Real m_volume; + int m_baudRate; + int m_squelchGate; + Real m_squelch; + bool m_audioMute; + bool m_syncOrConstellation; + quint32 m_rgbColor; + QString m_title; + bool m_highPassFilter; + int m_traceLengthMutliplier; // x 50ms + int m_traceStroke; // [0..255] + int m_traceDecay; // [0..255] + QString m_audioDeviceName; + int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). + bool m_useReverseAPI; + QString m_reverseAPIAddress; + uint16_t m_reverseAPIPort; + uint16_t m_reverseAPIDeviceIndex; + uint16_t m_reverseAPIChannelIndex; + int m_workspaceIndex; + QByteArray m_geometryBytes; + bool m_hidden; + + Serializable *m_channelMarker; + Serializable *m_rollupState; + + M17DemodSettings(); + 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_CHANNELRX_DEMODM17_M17DEMODSETTINGS_H_ */ diff --git a/plugins/channelrx/demodm17/m17demodsink.cpp b/plugins/channelrx/demodm17/m17demodsink.cpp new file mode 100644 index 000000000..f762f0781 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodsink.cpp @@ -0,0 +1,397 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "SWGChannelSettings.h" +#include "SWGDSDDemodSettings.h" +#include "SWGChannelReport.h" +#include "SWGDSDDemodReport.h" + +#include "dsp/dspengine.h" +#include "dsp/basebandsamplesink.h" +#include "dsp/datafifo.h" +#include "dsp/dspcommands.h" +#include "feature/feature.h" +#include "audio/audiooutputdevice.h" +#include "util/db.h" +#include "util/messagequeue.h" +#include "maincore.h" + +#include "m17demodsink.h" + +M17DemodSink::M17DemodSink() : + m_channelSampleRate(48000), + m_channelFrequencyOffset(0), + m_audioSampleRate(48000), + m_interpolatorDistance(0.0f), + m_interpolatorDistanceRemain(0.0f), + m_sampleCount(0), + m_squelchCount(0), + m_squelchGate(0), + m_squelchLevel(1e-4), + m_squelchOpen(false), + m_squelchDelayLine(24000), + m_audioFifo(48000), + m_scopeXY(nullptr), + m_scopeEnabled(true) +{ + m_audioBuffer.resize(1<<14); + m_audioBufferFill = 0; + m_demodBuffer.resize(1<<12); + m_demodBufferFill = 0; + + m_sampleBuffer = new FixReal[1<<17]; // 128 kS + m_sampleBufferIndex = 0; + m_scaleFromShort = SDR_RX_SAMP_SZ < sizeof(short)*8 ? 1 : 1<<(SDR_RX_SAMP_SZ - sizeof(short)*8); + + m_magsq = 0.0f; + m_magsqSum = 0.0f; + m_magsqPeak = 0.0f; + m_magsqCount = 0; + + applySettings(m_settings, true); + applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); +} + +M17DemodSink::~M17DemodSink() +{ + delete[] m_sampleBuffer; +} + +void M17DemodSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) +{ + Complex ci; + int samplesPerSymbol = 10; + + m_scopeSampleBuffer.clear(); + + for (SampleVector::const_iterator it = begin; it != end; ++it) + { + Complex c(it->real(), it->imag()); + c *= m_nco.nextIQ(); + + if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci)) + { + FixReal sample, delayedSample; + qint16 sampleM17; + + Real re = ci.real() / SDR_RX_SCALED; + Real im = ci.imag() / SDR_RX_SCALED; + Real magsq = re*re + im*im; + m_movingAverage(magsq); + + m_magsqSum += magsq; + + if (magsq > m_magsqPeak) + { + m_magsqPeak = magsq; + } + + m_magsqCount++; + + Real demod = m_phaseDiscri.phaseDiscriminator(ci) * m_settings.m_demodGain; // [-1.0:1.0] + m_sampleCount++; + + // AF processing + + if (m_movingAverage.asDouble() > m_squelchLevel) + { + if (m_squelchGate > 0) + { + + if (m_squelchCount < m_squelchGate*2) { + m_squelchCount++; + } + + m_squelchDelayLine.write(demod); + m_squelchOpen = m_squelchCount > m_squelchGate; + } + else + { + m_squelchOpen = true; + } + } + else + { + if (m_squelchGate > 0) + { + if (m_squelchCount > 0) { + m_squelchCount--; + } + + m_squelchDelayLine.write(0); + m_squelchOpen = m_squelchCount > m_squelchGate; + } + else + { + m_squelchOpen = false; + } + } + + if (m_squelchOpen) + { + if (m_squelchGate > 0) + { + sampleM17 = m_squelchDelayLine.readBack(m_squelchGate) * 32768.0f; // DSD decoder takes int16 samples + sample = m_squelchDelayLine.readBack(m_squelchGate) * SDR_RX_SCALEF; // scale to sample size + } + else + { + sampleM17 = demod * 32768.0f; // M17 decoder takes int16 samples + sample = demod * SDR_RX_SCALEF; // scale to sample size + } + } + else + { + sampleM17 = 0; + sample = 0; + } + + // m_dsdDecoder.pushSample(sampleM17); + + m_demodBuffer[m_demodBufferFill] = sampleM17; + ++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; + } + + // if (m_settings.m_enableCosineFiltering) { // show actual input to FSK demod + // sample = m_dsdDecoder.getFilteredSample() * m_scaleFromShort; + // } + + if (m_sampleBufferIndex < (1<<17)-1) { + m_sampleBufferIndex++; + } else { + m_sampleBufferIndex = 0; + } + + m_sampleBuffer[m_sampleBufferIndex] = sample; + + if (m_sampleBufferIndex < samplesPerSymbol) { + delayedSample = m_sampleBuffer[(1<<17) - samplesPerSymbol + m_sampleBufferIndex]; // wrap + } else { + delayedSample = m_sampleBuffer[m_sampleBufferIndex - samplesPerSymbol]; + } + + // if (m_settings.m_syncOrConstellation) + // { + // Sample s(sample, m_dsdDecoder.getSymbolSyncSample() * m_scaleFromShort * 0.84); + // m_scopeSampleBuffer.push_back(s); + // } + // else + // { + Sample s(sample, delayedSample); // I=signal, Q=signal delayed by 20 samples (2400 baud: lowest rate) + m_scopeSampleBuffer.push_back(s); + // } + + m_interpolatorDistanceRemain += m_interpolatorDistance; + } + } + + // if (!m_ambeFeature) + // { + // if (m_settings.m_slot1On) + // { + // int nbAudioSamples; + // short *dsdAudio = m_dsdDecoder.getAudio1(nbAudioSamples); + + // if (nbAudioSamples > 0) + // { + // if (!m_settings.m_audioMute) { + // m_audioFifo1.write((const quint8*) dsdAudio, nbAudioSamples); + // } + + // m_dsdDecoder.resetAudio1(); + // } + // } + + // if (m_settings.m_slot2On) + // { + // int nbAudioSamples; + // short *dsdAudio = m_dsdDecoder.getAudio2(nbAudioSamples); + + // if (nbAudioSamples > 0) + // { + // if (!m_settings.m_audioMute) { + // m_audioFifo2.write((const quint8*) dsdAudio, nbAudioSamples); + // } + + // m_dsdDecoder.resetAudio2(); + // } + // } + // } + + if ((m_scopeXY != nullptr) && (m_scopeEnabled)) + { + m_scopeXY->feed(m_scopeSampleBuffer.begin(), m_scopeSampleBuffer.end(), true); // true = real samples for what it's worth + } +} + +void M17DemodSink::applyAudioSampleRate(int sampleRate) +{ + if (sampleRate < 0) + { + qWarning("M17DemodSink::applyAudioSampleRate: invalid sample rate: %d", sampleRate); + return; + } + + int upsampling = sampleRate / 8000; + + qDebug("M17DemodSink::applyAudioSampleRate: audio rate: %d upsample by %d", sampleRate, upsampling); + + if (sampleRate % 8000 != 0) { + qDebug("M17DemodSink::applyAudioSampleRate: audio will sound best with sample rates that are integer multiples of 8 kS/s"); + } + + // m_dsdDecoder.setUpsampling(upsampling); + m_audioSampleRate = sampleRate; + + 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, sampleRate); + messageQueue->push(msg); + } + } +} + +void M17DemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) +{ + qDebug() << "DSDDemodSink::applyChannelSettings:" + << " channelSampleRate: " << channelSampleRate + << " inputFrequencyOffset: " << channelFrequencyOffset; + + if ((channelFrequencyOffset != m_channelFrequencyOffset) || + (channelSampleRate != m_channelSampleRate) || force) + { + m_nco.setFreq(-channelFrequencyOffset, channelSampleRate); + } + + if ((channelSampleRate != m_channelSampleRate) || force) + { + m_interpolator.create(16, channelSampleRate, (m_settings.m_rfBandwidth) / 2.2); + m_interpolatorDistanceRemain = 0; + m_interpolatorDistance = (Real) channelSampleRate / (Real) 48000; + } + + m_channelSampleRate = channelSampleRate; + m_channelFrequencyOffset = channelFrequencyOffset; +} + + +void M17DemodSink::applySettings(const M17DemodSettings& settings, bool force) +{ + qDebug() << "M17DemodSink::applySettings: " + << " m_inputFrequencyOffset: " << settings.m_inputFrequencyOffset + << " m_rfBandwidth: " << settings.m_rfBandwidth + << " m_fmDeviation: " << settings.m_fmDeviation + << " m_demodGain: " << settings.m_demodGain + << " m_volume: " << settings.m_volume + << " m_baudRate: " << settings.m_baudRate + << " m_squelchGate" << settings.m_squelchGate + << " m_squelch: " << settings.m_squelch + << " m_audioMute: " << settings.m_audioMute + << " m_syncOrConstellation: " << settings.m_syncOrConstellation + << " m_highPassFilter: "<< settings.m_highPassFilter + << " m_audioDeviceName: " << settings.m_audioDeviceName + << " m_traceLengthMutliplier: " << settings.m_traceLengthMutliplier + << " m_traceStroke: " << settings.m_traceStroke + << " m_traceDecay: " << settings.m_traceDecay + << " m_streamIndex: " << settings.m_streamIndex + << " force: " << force; + + if ((settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force) + { + m_interpolator.create(16, m_channelSampleRate, (settings.m_rfBandwidth) / 2.2); + m_interpolatorDistanceRemain = 0; + m_interpolatorDistance = (Real) m_channelSampleRate / (Real) 48000; + //m_phaseDiscri.setFMScaling((float) settings.m_rfBandwidth / (float) settings.m_fmDeviation); + } + + if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force) + { + m_phaseDiscri.setFMScaling(48000.0f / (2.0f*settings.m_fmDeviation)); + } + + if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) + { + m_squelchGate = 480 * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate + m_squelchCount = 0; // reset squelch open counter + } + + if ((settings.m_squelch != m_settings.m_squelch) || force) + { + // input is a value in dB + m_squelchLevel = std::pow(10.0, settings.m_squelch / 10.0); + } + + if ((settings.m_volume != m_settings.m_volume) || force) + { + // m_dsdDecoder.setAudioGain(settings.m_volume); + } + + if ((settings.m_baudRate != m_settings.m_baudRate) || force) + { + // m_dsdDecoder.setBaudRate(settings.m_baudRate); + } + + if ((settings.m_highPassFilter != m_settings.m_highPassFilter) || force) + { + // m_dsdDecoder.useHPMbelib(settings.m_highPassFilter); + } + + m_settings = settings; +} + +void M17DemodSink::configureMyPosition(float myLatitude, float myLongitude) +{ + // m_dsdDecoder.setMyPoint(myLatitude, myLongitude); +} + diff --git a/plugins/channelrx/demodm17/m17demodsink.h b/plugins/channelrx/demodm17/m17demodsink.h new file mode 100644 index 000000000..da8d7d447 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodsink.h @@ -0,0 +1,134 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 Edouard Griffiths, F4EXB // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_M17DEMODSINK_H +#define INCLUDE_M17DEMODSINK_H + +#include + +#include "dsp/channelsamplesink.h" +#include "dsp/phasediscri.h" +#include "dsp/nco.h" +#include "dsp/interpolator.h" +#include "dsp/firfilter.h" +#include "dsp/afsquelch.h" +#include "dsp/afsquelch.h" +#include "audio/audiofifo.h" +#include "util/movingaverage.h" +#include "util/doublebufferfifo.h" + +#include "m17demodsettings.h" + +class BasebandSampleSink; +class ChannelAPI; + +class M17DemodSink : public ChannelSampleSink { +public: + M17DemodSink(); + ~M17DemodSink(); + + virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end); + + void applyAudioSampleRate(int sampleRate); + void applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force = false); + void applySettings(const M17DemodSettings& settings, bool force = false); + AudioFifo *getAudioFifo() { return &m_audioFifo; } + void setAudioFifoLabel(const QString& label) { m_audioFifo.setLabel("1:" + label); } + int getAudioSampleRate() const { return m_audioSampleRate; } + void setChannel(ChannelAPI *channel) { m_channel = channel; } + + void setScopeXYSink(BasebandSampleSink* scopeSink) { m_scopeXY = scopeSink; } + void configureMyPosition(float myLatitude, float myLongitude); + + double getMagSq() { return m_magsq; } + bool getSquelchOpen() const { return m_squelchOpen; } + + void getMagSqLevels(double& avg, double& peak, int& nbSamples) + { + if (m_magsqCount > 0) + { + m_magsq = m_magsqSum / m_magsqCount; + m_magSqLevelStore.m_magsq = m_magsq; + m_magSqLevelStore.m_magsqPeak = m_magsqPeak; + } + + avg = m_magSqLevelStore.m_magsq; + peak = m_magSqLevelStore.m_magsqPeak; + nbSamples = m_magsqCount == 0 ? 1 : m_magsqCount; + + m_magsqSum = 0.0f; + m_magsqPeak = 0.0f; + m_magsqCount = 0; + } + +private: + struct MagSqLevelsStore + { + MagSqLevelsStore() : + m_magsq(1e-12), + m_magsqPeak(1e-12) + {} + double m_magsq; + double m_magsqPeak; + }; + + enum RateState { + RSInitialFill, + RSRunning + }; + + int m_channelSampleRate; + int m_channelFrequencyOffset; + M17DemodSettings m_settings; + ChannelAPI *m_channel; + int m_audioSampleRate; + QVector m_demodBuffer; + int m_demodBufferFill; + + NCO m_nco; + Interpolator m_interpolator; + Real m_interpolatorDistance; + Real m_interpolatorDistanceRemain; + int m_sampleCount; + int m_squelchCount; + int m_squelchGate; + double m_squelchLevel; + bool m_squelchOpen; + DoubleBufferFIFO m_squelchDelayLine; + + MovingAverageUtil m_movingAverage; + double m_magsq; + double m_magsqSum; + double m_magsqPeak; + int m_magsqCount; + MagSqLevelsStore m_magSqLevelStore; + + SampleVector m_scopeSampleBuffer; + AudioVector m_audioBuffer; + uint m_audioBufferFill; + FixReal *m_sampleBuffer; //!< samples ring buffer + int m_sampleBufferIndex; + int m_scaleFromShort; + + AudioFifo m_audioFifo; + BasebandSampleSink* m_scopeXY; + bool m_scopeEnabled; + + PhaseDiscriminators m_phaseDiscri; +}; + +#endif // INCLUDE_DSDDEMODSINK_H diff --git a/plugins/channelrx/demodm17/m17demodwebapiadapter.cpp b/plugins/channelrx/demodm17/m17demodwebapiadapter.cpp new file mode 100644 index 000000000..58be09f29 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodwebapiadapter.cpp @@ -0,0 +1,51 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 Edouard Griffiths, F4EXB. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "SWGChannelSettings.h" +#include "m17demod.h" +#include "m17demodwebapiadapter.h" + +M17DemodWebAPIAdapter::M17DemodWebAPIAdapter() +{} + +M17DemodWebAPIAdapter::~M17DemodWebAPIAdapter() +{} + +int M17DemodWebAPIAdapter::webapiSettingsGet( + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage) +{ + (void) errorMessage; + response.setDsdDemodSettings(new SWGSDRangel::SWGDSDDemodSettings()); + response.getDsdDemodSettings()->init(); + M17Demod::webapiFormatChannelSettings(response, m_settings); + + return 200; +} + +int M17DemodWebAPIAdapter::webapiSettingsPutPatch( + bool force, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage) +{ + (void) force; // no action + (void) errorMessage; + M17Demod::webapiUpdateChannelSettings(m_settings, channelSettingsKeys, response); + + return 200; +} diff --git a/plugins/channelrx/demodm17/m17demodwebapiadapter.h b/plugins/channelrx/demodm17/m17demodwebapiadapter.h new file mode 100644 index 000000000..40c0e5236 --- /dev/null +++ b/plugins/channelrx/demodm17/m17demodwebapiadapter.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 Edouard Griffiths, F4EXB. // +// // +// This program is free software; you can redistribute it and/or modify // +// it under the terms of the GNU General Public License as published by // +// the Free Software Foundation as version 3 of the License, or // +// (at your option) any later version. // +// // +// This program is distributed in the hope that it will be useful, // +// but WITHOUT ANY WARRANTY; without even the implied warranty of // +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // +// GNU General Public License V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef INCLUDE_M17DEMOD_WEBAPIADAPTER_H +#define INCLUDE_M17DEMOD_WEBAPIADAPTER_H + +#include "channel/channelwebapiadapter.h" +#include "m17demodsettings.h" + +/** + * Standalone API adapter only for the settings + */ +class M17DemodWebAPIAdapter : public ChannelWebAPIAdapter { +public: + M17DemodWebAPIAdapter(); + virtual ~M17DemodWebAPIAdapter(); + + 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: + M17DemodSettings m_settings; +}; + +#endif // INCLUDE_M17DEMOD_WEBAPIADAPTER_H diff --git a/plugins/channelrx/demodm17/m17statustextdialog.cpp b/plugins/channelrx/demodm17/m17statustextdialog.cpp new file mode 100644 index 000000000..b1de33434 --- /dev/null +++ b/plugins/channelrx/demodm17/m17statustextdialog.cpp @@ -0,0 +1,88 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022s F4EXB // +// written by Edouard Griffiths // +// // +// 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 "m17statustextdialog.h" +#include "ui_m17statustextdialog.h" + +#include +#include +#include +#include +#include + +M17StatusTextDialog::M17StatusTextDialog(QWidget* parent) : + QDialog(parent), + ui(new Ui::M17StatusTextDialog) +{ + ui->setupUi(this); +} + +M17StatusTextDialog::~M17StatusTextDialog() +{ + delete ui; +} + +void M17StatusTextDialog::addLine(const QString& line) +{ + if ((line.size() > 0) && (line != m_lastLine)) + { + QDateTime dt = QDateTime::currentDateTime(); + QString dateStr = dt.toString("HH:mm:ss"); + QTextCursor cursor = ui->logEdit->textCursor(); + cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); + cursor.insertText(tr("%1 %2\n").arg(dateStr).arg(line)); + if (ui->pinToLastLine->isChecked()) { + ui->logEdit->verticalScrollBar()->setValue(ui->logEdit->verticalScrollBar()->maximum()); + } + m_lastLine = line; + } +} + +void M17StatusTextDialog::on_clear_clicked() +{ + ui->logEdit->clear(); +} + +void M17StatusTextDialog::on_saveLog_clicked() +{ + QString fileName = QFileDialog::getSaveFileName(this, + tr("Open log file"), ".", tr("Log files (*.log)"), 0, QFileDialog::DontUseNativeDialog); + + if (fileName != "") + { + QFileInfo fileInfo(fileName); + + if (fileInfo.suffix() != "log") { + fileName += ".log"; + } + + QFile exportFile(fileName); + + if (exportFile.open(QIODevice::WriteOnly | QIODevice::Text)) + { + QTextStream outstream(&exportFile); + outstream << ui->logEdit->toPlainText(); + exportFile.close(); + } + else + { + QMessageBox::information(this, tr("Message"), tr("Cannot open file for writing")); + } + } + +} diff --git a/plugins/channelrx/demodm17/m17statustextdialog.h b/plugins/channelrx/demodm17/m17statustextdialog.h new file mode 100644 index 000000000..2158d9b44 --- /dev/null +++ b/plugins/channelrx/demodm17/m17statustextdialog.h @@ -0,0 +1,47 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2022 F4EXB // +// written by Edouard Griffiths // +// // +// 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_CHANNELRX_DEMODM17_M17STATUSTEXTDIALOG_H_ +#define PLUGINS_CHANNELRX_DEMODM17_M17STATUSTEXTDIALOG_H_ + +#include + +namespace Ui { + class M17StatusTextDialog; +} + +class M17StatusTextDialog : public QDialog { + Q_OBJECT + +public: + explicit M17StatusTextDialog(QWidget* parent = nullptr); + ~M17StatusTextDialog(); + + void addLine(const QString& line); + +private: + Ui::M17StatusTextDialog* ui; + QString m_lastLine; + +private slots: + void on_clear_clicked(); + void on_saveLog_clicked(); +}; + + +#endif /* PLUGINS_CHANNELRX_DEMODM17_M17STATUSTEXTDIALOG_H_ */ diff --git a/plugins/channelrx/demodm17/m17statustextdialog.ui b/plugins/channelrx/demodm17/m17statustextdialog.ui new file mode 100644 index 000000000..a3130d47d --- /dev/null +++ b/plugins/channelrx/demodm17/m17statustextdialog.ui @@ -0,0 +1,181 @@ + + + M17StatusTextDialog + + + + 0 + 0 + 740 + 380 + + + + + Sans Serif + 9 + + + + Status text log + + + + :/sdrangel_icon.png:/sdrangel_icon.png + + + + + + + + + 24 + 24 + + + + Clear log + + + + + + + :/sweep.png:/sweep.png + + + false + + + + + + + Pin to last line + + + + + + + :/pin_last.png:/pin_last.png + + + + + + + + 24 + 24 + + + + Save log to file + + + + + + + :/save.png:/save.png + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + true + + + + Liberation Mono + + + + Log + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+
+ + buttonBox + + + + + + + buttonBox + accepted() + DSDStatusTextDialog + accept() + + + 257 + 194 + + + 157 + 203 + + + + + buttonBox + rejected() + DSDStatusTextDialog + reject() + + + 314 + 194 + + + 286 + 203 + + + + +
diff --git a/sdrbase/resources/webapi.qrc b/sdrbase/resources/webapi.qrc index 7e941bf14..bb93cc0cb 100644 --- a/sdrbase/resources/webapi.qrc +++ b/sdrbase/resources/webapi.qrc @@ -69,6 +69,7 @@ webapi/doc/swagger/include/LocalSource.yaml webapi/doc/swagger/include/Map.yaml webapi/doc/swagger/include/MetisMISO.yaml + webapi/doc/swagger/include/M17Demod.yaml webapi/doc/swagger/include/NFMDemod.yaml webapi/doc/swagger/include/NFMMod.yaml webapi/doc/swagger/include/NoiseFigure.yaml diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index 3efca3e1a..0a3ce0758 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -3421,6 +3421,9 @@ margin-bottom: 20px; "FreqTrackerReport" : { "$ref" : "#/definitions/FreqTrackerReport" }, + "M17DemodReport" : { + "$ref" : "#/definitions/M17DemodReport" + }, "NFMDemodReport" : { "$ref" : "#/definitions/NFMDemodReport" }, @@ -3573,6 +3576,9 @@ margin-bottom: 20px; "IEEE_802_15_4_ModSettings" : { "$ref" : "#/definitions/IEEE_802_15_4_ModSettings" }, + "M17DemodSettings" : { + "$ref" : "#/definitions/M17DemodSettings" + }, "NFMDemodSettings" : { "$ref" : "#/definitions/NFMDemodSettings" }, @@ -8210,6 +8216,120 @@ margin-bottom: 20px; } }, "description" : "Logging parameters setting" +}; + defs.M17DemodReport = { + "properties" : { + "channelPowerDB" : { + "type" : "number", + "format" : "float", + "description" : "power transmitted in channel (dB)" + }, + "audioSampleRate" : { + "type" : "integer" + }, + "channelSampleRate" : { + "type" : "integer" + }, + "squelch" : { + "type" : "integer", + "description" : "squelch status (1 if open else 0)" + } + }, + "description" : "M17Demod" +}; + defs.M17DemodSettings = { + "properties" : { + "inputFrequencyOffset" : { + "type" : "integer", + "format" : "int64" + }, + "rfBandwidth" : { + "type" : "number", + "format" : "float" + }, + "fmDeviation" : { + "type" : "number", + "format" : "float" + }, + "demodGain" : { + "type" : "number", + "format" : "float" + }, + "volume" : { + "type" : "number", + "format" : "float" + }, + "baudRate" : { + "type" : "integer" + }, + "squelchGate" : { + "type" : "integer" + }, + "squelch" : { + "type" : "number", + "format" : "float" + }, + "audioMute" : { + "type" : "integer" + }, + "syncOrConstellation" : { + "type" : "integer" + }, + "pllLock" : { + "type" : "integer" + }, + "rgbColor" : { + "type" : "integer" + }, + "title" : { + "type" : "string" + }, + "audioDeviceName" : { + "type" : "string" + }, + "highPassFilter" : { + "type" : "integer" + }, + "traceLengthMutliplier" : { + "type" : "integer", + "description" : "multiply by 50ms" + }, + "traceStroke" : { + "type" : "integer", + "description" : "0 to 255" + }, + "traceDecay" : { + "type" : "integer", + "description" : "0 to 255" + }, + "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" : "M17Demod" }; defs.MapActions = { "properties" : { @@ -56169,7 +56289,7 @@ except ApiException as e:
- Generated 2022-06-04T08:51:44.121+02:00 + Generated 2022-06-05T00:26:14.019+02:00
diff --git a/sdrbase/resources/webapi/doc/swagger/include/ChannelReport.yaml b/sdrbase/resources/webapi/doc/swagger/include/ChannelReport.yaml index 986ee1f58..ddc65e958 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/ChannelReport.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/ChannelReport.yaml @@ -49,6 +49,8 @@ ChannelReport: $ref: "/doc/swagger/include/FreeDVMod.yaml#/FreeDVModReport" FreqTrackerReport: $ref: "/doc/swagger/include/FreqTracker.yaml#/FreqTrackerReport" + M17DemodReport: + $ref: "/doc/swagger/include/M17Demod.yaml#/M17DemodReport" NFMDemodReport: $ref: "/doc/swagger/include/NFMDemod.yaml#/NFMDemodReport" NFMModReport: diff --git a/sdrbase/resources/webapi/doc/swagger/include/ChannelSettings.yaml b/sdrbase/resources/webapi/doc/swagger/include/ChannelSettings.yaml index c3a73c9d5..6833684ef 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/ChannelSettings.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/ChannelSettings.yaml @@ -67,6 +67,8 @@ ChannelSettings: $ref: "/doc/swagger/include/Interferometer.yaml#/InterferometerSettings" IEEE_802_15_4_ModSettings: $ref: "/doc/swagger/include/IEEE_802_15_4_Mod.yaml#/IEEE_802_15_4_ModSettings" + M17DemodSettings: + $ref: "/doc/swagger/include/M17Demod.yaml#/M17DemodSettings" NFMDemodSettings: $ref: "/doc/swagger/include/NFMDemod.yaml#/NFMDemodSettings" NFMModSettings: diff --git a/sdrbase/resources/webapi/doc/swagger/include/M17Demod.yaml b/sdrbase/resources/webapi/doc/swagger/include/M17Demod.yaml new file mode 100644 index 000000000..dba704540 --- /dev/null +++ b/sdrbase/resources/webapi/doc/swagger/include/M17Demod.yaml @@ -0,0 +1,82 @@ +M17DemodSettings: + description: M17Demod + properties: + inputFrequencyOffset: + type: integer + format: int64 + rfBandwidth: + type: number + format: float + fmDeviation: + type: number + format: float + demodGain: + type: number + format: float + volume: + type: number + format: float + baudRate: + type: integer + squelchGate: + type: integer + squelch: + type: number + format: float + audioMute: + type: integer + syncOrConstellation: + type: integer + pllLock: + type: integer + rgbColor: + type: integer + title: + type: string + audioDeviceName: + type: string + highPassFilter: + type: integer + traceLengthMutliplier: + description: multiply by 50ms + type: integer + traceStroke: + description: 0 to 255 + type: integer + traceDecay: + description: 0 to 255 + type: integer + 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: "/doc/swagger/include/ChannelMarker.yaml#/ChannelMarker" + rollupState: + $ref: "/doc/swagger/include/RollupState.yaml#/RollupState" + +M17DemodReport: + description: M17Demod + properties: + channelPowerDB: + description: power transmitted in channel (dB) + type: number + format: float + audioSampleRate: + type: integer + channelSampleRate: + type: integer + squelch: + description: squelch status (1 if open else 0) + type: integer + diff --git a/sdrbase/webapi/webapirequestmapper.cpp b/sdrbase/webapi/webapirequestmapper.cpp index 17b2e8d6d..116a9ca87 100644 --- a/sdrbase/webapi/webapirequestmapper.cpp +++ b/sdrbase/webapi/webapirequestmapper.cpp @@ -4521,6 +4521,11 @@ bool WebAPIRequestMapper::getChannelSettings( channelSettings->setNfmDemodSettings(new SWGSDRangel::SWGNFMDemodSettings()); channelSettings->getNfmDemodSettings()->fromJsonObject(settingsJsonObject); } + else if (channelSettingsKey == "M17DemodSettings") + { + channelSettings->setM17DemodSettings(new SWGSDRangel::SWGM17DemodSettings()); + channelSettings->getM17DemodSettings()->fromJsonObject(settingsJsonObject); + } else if (channelSettingsKey == "NFMModSettings") { channelSettings->setNfmModSettings(new SWGSDRangel::SWGNFMModSettings()); diff --git a/sdrbase/webapi/webapiutils.cpp b/sdrbase/webapi/webapiutils.cpp index fdbb0024b..0c4c5b256 100644 --- a/sdrbase/webapi/webapiutils.cpp +++ b/sdrbase/webapi/webapiutils.cpp @@ -47,6 +47,7 @@ const QMap WebAPIUtils::m_channelURIToSettingsKey = { {"sdrangel.channel.freedvdemod", "FreeDVDemodSettings"}, {"sdrangel.channeltx.freedvmod", "FreeDVModSettings"}, {"sdrangel.channel.freqtracker", "FreqTrackerSettings"}, + {"sdrangel.channel.m17demod", "M17DemodSettings"}, {"sdrangel.channel.nfmdemod", "NFMDemodSettings"}, {"de.maintech.sdrangelove.channel.nfm", "NFMDemodSettings"}, // remap {"sdrangel.channeltx.modnfm", "NFMModSettings"}, @@ -153,6 +154,7 @@ const QMap WebAPIUtils::m_channelTypeToSettingsKey = { {"FreeDVMod", "FreeDVModSettings"}, {"FreqTracker", "FreqTrackerSettings"}, {"IEEE_802_15_4_Mod", "IEEE_802_15_4_ModSettings"}, + {"M17Demod", "M17DemodSettings"}, {"NFMDemod", "NFMDemodSettings"}, {"NFMMod", "NFMModSettings"}, {"NoiseFigure", "NoiseFigureSettings"}, diff --git a/swagger/sdrangel/api/swagger/include/ChannelReport.yaml b/swagger/sdrangel/api/swagger/include/ChannelReport.yaml index 548d2ba87..517b84493 100644 --- a/swagger/sdrangel/api/swagger/include/ChannelReport.yaml +++ b/swagger/sdrangel/api/swagger/include/ChannelReport.yaml @@ -49,6 +49,8 @@ ChannelReport: $ref: "http://swgserver:8081/api/swagger/include/FreeDVMod.yaml#/FreeDVModReport" FreqTrackerReport: $ref: "http://swgserver:8081/api/swagger/include/FreqTracker.yaml#/FreqTrackerReport" + M17DemodReport: + $ref: "http://swgserver:8081/api/swagger/include/M17Demod.yaml#/M17DemodReport" NFMDemodReport: $ref: "http://swgserver:8081/api/swagger/include/NFMDemod.yaml#/NFMDemodReport" NFMModReport: diff --git a/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml b/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml index 5125d53ad..0e1bc4723 100644 --- a/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml +++ b/swagger/sdrangel/api/swagger/include/ChannelSettings.yaml @@ -67,6 +67,8 @@ ChannelSettings: $ref: "http://swgserver:8081/api/swagger/include/Interferometer.yaml#/InterferometerSettings" IEEE_802_15_4_ModSettings: $ref: "http://swgserver:8081/api/swagger/include/IEEE_802_15_4_Mod.yaml#/IEEE_802_15_4_ModSettings" + M17DemodSettings: + $ref: "http://swgserver:8081/api/swagger/include/M17Demod.yaml#/M17DemodSettings" NFMDemodSettings: $ref: "http://swgserver:8081/api/swagger/include/NFMDemod.yaml#/NFMDemodSettings" NFMModSettings: diff --git a/swagger/sdrangel/api/swagger/include/M17Demod.yaml b/swagger/sdrangel/api/swagger/include/M17Demod.yaml new file mode 100644 index 000000000..d4ab21f53 --- /dev/null +++ b/swagger/sdrangel/api/swagger/include/M17Demod.yaml @@ -0,0 +1,82 @@ +M17DemodSettings: + description: M17Demod + properties: + inputFrequencyOffset: + type: integer + format: int64 + rfBandwidth: + type: number + format: float + fmDeviation: + type: number + format: float + demodGain: + type: number + format: float + volume: + type: number + format: float + baudRate: + type: integer + squelchGate: + type: integer + squelch: + type: number + format: float + audioMute: + type: integer + syncOrConstellation: + type: integer + pllLock: + type: integer + rgbColor: + type: integer + title: + type: string + audioDeviceName: + type: string + highPassFilter: + type: integer + traceLengthMutliplier: + description: multiply by 50ms + type: integer + traceStroke: + description: 0 to 255 + type: integer + traceDecay: + description: 0 to 255 + type: integer + 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" + +M17DemodReport: + description: M17Demod + properties: + channelPowerDB: + description: power transmitted in channel (dB) + type: number + format: float + audioSampleRate: + type: integer + channelSampleRate: + type: integer + squelch: + description: squelch status (1 if open else 0) + type: integer + diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index 3efca3e1a..0a3ce0758 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -3421,6 +3421,9 @@ margin-bottom: 20px; "FreqTrackerReport" : { "$ref" : "#/definitions/FreqTrackerReport" }, + "M17DemodReport" : { + "$ref" : "#/definitions/M17DemodReport" + }, "NFMDemodReport" : { "$ref" : "#/definitions/NFMDemodReport" }, @@ -3573,6 +3576,9 @@ margin-bottom: 20px; "IEEE_802_15_4_ModSettings" : { "$ref" : "#/definitions/IEEE_802_15_4_ModSettings" }, + "M17DemodSettings" : { + "$ref" : "#/definitions/M17DemodSettings" + }, "NFMDemodSettings" : { "$ref" : "#/definitions/NFMDemodSettings" }, @@ -8210,6 +8216,120 @@ margin-bottom: 20px; } }, "description" : "Logging parameters setting" +}; + defs.M17DemodReport = { + "properties" : { + "channelPowerDB" : { + "type" : "number", + "format" : "float", + "description" : "power transmitted in channel (dB)" + }, + "audioSampleRate" : { + "type" : "integer" + }, + "channelSampleRate" : { + "type" : "integer" + }, + "squelch" : { + "type" : "integer", + "description" : "squelch status (1 if open else 0)" + } + }, + "description" : "M17Demod" +}; + defs.M17DemodSettings = { + "properties" : { + "inputFrequencyOffset" : { + "type" : "integer", + "format" : "int64" + }, + "rfBandwidth" : { + "type" : "number", + "format" : "float" + }, + "fmDeviation" : { + "type" : "number", + "format" : "float" + }, + "demodGain" : { + "type" : "number", + "format" : "float" + }, + "volume" : { + "type" : "number", + "format" : "float" + }, + "baudRate" : { + "type" : "integer" + }, + "squelchGate" : { + "type" : "integer" + }, + "squelch" : { + "type" : "number", + "format" : "float" + }, + "audioMute" : { + "type" : "integer" + }, + "syncOrConstellation" : { + "type" : "integer" + }, + "pllLock" : { + "type" : "integer" + }, + "rgbColor" : { + "type" : "integer" + }, + "title" : { + "type" : "string" + }, + "audioDeviceName" : { + "type" : "string" + }, + "highPassFilter" : { + "type" : "integer" + }, + "traceLengthMutliplier" : { + "type" : "integer", + "description" : "multiply by 50ms" + }, + "traceStroke" : { + "type" : "integer", + "description" : "0 to 255" + }, + "traceDecay" : { + "type" : "integer", + "description" : "0 to 255" + }, + "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" : "M17Demod" }; defs.MapActions = { "properties" : { @@ -56169,7 +56289,7 @@ except ApiException as e:
- Generated 2022-06-04T08:51:44.121+02:00 + Generated 2022-06-05T00:26:14.019+02:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelReport.cpp b/swagger/sdrangel/code/qt5/client/SWGChannelReport.cpp index 8759fbce4..686f24dca 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelReport.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGChannelReport.cpp @@ -70,6 +70,8 @@ SWGChannelReport::SWGChannelReport() { m_free_dv_mod_report_isSet = false; freq_tracker_report = nullptr; m_freq_tracker_report_isSet = false; + m17_demod_report = nullptr; + m_m17_demod_report_isSet = false; nfm_demod_report = nullptr; m_nfm_demod_report_isSet = false; nfm_mod_report = nullptr; @@ -156,6 +158,8 @@ SWGChannelReport::init() { m_free_dv_mod_report_isSet = false; freq_tracker_report = new SWGFreqTrackerReport(); m_freq_tracker_report_isSet = false; + m17_demod_report = new SWGM17DemodReport(); + m_m17_demod_report_isSet = false; nfm_demod_report = new SWGNFMDemodReport(); m_nfm_demod_report_isSet = false; nfm_mod_report = new SWGNFMModReport(); @@ -257,6 +261,9 @@ SWGChannelReport::cleanup() { if(freq_tracker_report != nullptr) { delete freq_tracker_report; } + if(m17_demod_report != nullptr) { + delete m17_demod_report; + } if(nfm_demod_report != nullptr) { delete nfm_demod_report; } @@ -366,6 +373,8 @@ SWGChannelReport::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&freq_tracker_report, pJson["FreqTrackerReport"], "SWGFreqTrackerReport", "SWGFreqTrackerReport"); + ::SWGSDRangel::setValue(&m17_demod_report, pJson["M17DemodReport"], "SWGM17DemodReport", "SWGM17DemodReport"); + ::SWGSDRangel::setValue(&nfm_demod_report, pJson["NFMDemodReport"], "SWGNFMDemodReport", "SWGNFMDemodReport"); ::SWGSDRangel::setValue(&nfm_mod_report, pJson["NFMModReport"], "SWGNFMModReport", "SWGNFMModReport"); @@ -481,6 +490,9 @@ SWGChannelReport::asJsonObject() { if((freq_tracker_report != nullptr) && (freq_tracker_report->isSet())){ toJsonValue(QString("FreqTrackerReport"), freq_tracker_report, obj, QString("SWGFreqTrackerReport")); } + if((m17_demod_report != nullptr) && (m17_demod_report->isSet())){ + toJsonValue(QString("M17DemodReport"), m17_demod_report, obj, QString("SWGM17DemodReport")); + } if((nfm_demod_report != nullptr) && (nfm_demod_report->isSet())){ toJsonValue(QString("NFMDemodReport"), nfm_demod_report, obj, QString("SWGNFMDemodReport")); } @@ -749,6 +761,16 @@ SWGChannelReport::setFreqTrackerReport(SWGFreqTrackerReport* freq_tracker_report this->m_freq_tracker_report_isSet = true; } +SWGM17DemodReport* +SWGChannelReport::getM17DemodReport() { + return m17_demod_report; +} +void +SWGChannelReport::setM17DemodReport(SWGM17DemodReport* m17_demod_report) { + this->m17_demod_report = m17_demod_report; + this->m_m17_demod_report_isSet = true; +} + SWGNFMDemodReport* SWGChannelReport::getNfmDemodReport() { return nfm_demod_report; @@ -997,6 +1019,9 @@ SWGChannelReport::isSet(){ if(freq_tracker_report && freq_tracker_report->isSet()){ isObjectUpdated = true; break; } + if(m17_demod_report && m17_demod_report->isSet()){ + isObjectUpdated = true; break; + } if(nfm_demod_report && nfm_demod_report->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelReport.h b/swagger/sdrangel/code/qt5/client/SWGChannelReport.h index 9d2e66a79..aa6174786 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelReport.h +++ b/swagger/sdrangel/code/qt5/client/SWGChannelReport.h @@ -41,6 +41,7 @@ #include "SWGFreeDVModReport.h" #include "SWGFreqTrackerReport.h" #include "SWGIEEE_802_15_4_ModReport.h" +#include "SWGM17DemodReport.h" #include "SWGNFMDemodReport.h" #include "SWGNFMModReport.h" #include "SWGNoiseFigureReport.h" @@ -142,6 +143,9 @@ public: SWGFreqTrackerReport* getFreqTrackerReport(); void setFreqTrackerReport(SWGFreqTrackerReport* freq_tracker_report); + SWGM17DemodReport* getM17DemodReport(); + void setM17DemodReport(SWGM17DemodReport* m17_demod_report); + SWGNFMDemodReport* getNfmDemodReport(); void setNfmDemodReport(SWGNFMDemodReport* nfm_demod_report); @@ -263,6 +267,9 @@ private: SWGFreqTrackerReport* freq_tracker_report; bool m_freq_tracker_report_isSet; + SWGM17DemodReport* m17_demod_report; + bool m_m17_demod_report_isSet; + SWGNFMDemodReport* nfm_demod_report; bool m_nfm_demod_report_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp index 7c77c3aba..344c697f5 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.cpp @@ -86,6 +86,8 @@ SWGChannelSettings::SWGChannelSettings() { m_interferometer_settings_isSet = false; ieee_802_15_4_mod_settings = nullptr; m_ieee_802_15_4_mod_settings_isSet = false; + m17_demod_settings = nullptr; + m_m17_demod_settings_isSet = false; nfm_demod_settings = nullptr; m_nfm_demod_settings_isSet = false; nfm_mod_settings = nullptr; @@ -194,6 +196,8 @@ SWGChannelSettings::init() { m_interferometer_settings_isSet = false; ieee_802_15_4_mod_settings = new SWGIEEE_802_15_4_ModSettings(); m_ieee_802_15_4_mod_settings_isSet = false; + m17_demod_settings = new SWGM17DemodSettings(); + m_m17_demod_settings_isSet = false; nfm_demod_settings = new SWGNFMDemodSettings(); m_nfm_demod_settings_isSet = false; nfm_mod_settings = new SWGNFMModSettings(); @@ -321,6 +325,9 @@ SWGChannelSettings::cleanup() { if(ieee_802_15_4_mod_settings != nullptr) { delete ieee_802_15_4_mod_settings; } + if(m17_demod_settings != nullptr) { + delete m17_demod_settings; + } if(nfm_demod_settings != nullptr) { delete nfm_demod_settings; } @@ -455,6 +462,8 @@ SWGChannelSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&ieee_802_15_4_mod_settings, pJson["IEEE_802_15_4_ModSettings"], "SWGIEEE_802_15_4_ModSettings", "SWGIEEE_802_15_4_ModSettings"); + ::SWGSDRangel::setValue(&m17_demod_settings, pJson["M17DemodSettings"], "SWGM17DemodSettings", "SWGM17DemodSettings"); + ::SWGSDRangel::setValue(&nfm_demod_settings, pJson["NFMDemodSettings"], "SWGNFMDemodSettings", "SWGNFMDemodSettings"); ::SWGSDRangel::setValue(&nfm_mod_settings, pJson["NFMModSettings"], "SWGNFMModSettings", "SWGNFMModSettings"); @@ -600,6 +609,9 @@ SWGChannelSettings::asJsonObject() { if((ieee_802_15_4_mod_settings != nullptr) && (ieee_802_15_4_mod_settings->isSet())){ toJsonValue(QString("IEEE_802_15_4_ModSettings"), ieee_802_15_4_mod_settings, obj, QString("SWGIEEE_802_15_4_ModSettings")); } + if((m17_demod_settings != nullptr) && (m17_demod_settings->isSet())){ + toJsonValue(QString("M17DemodSettings"), m17_demod_settings, obj, QString("SWGM17DemodSettings")); + } if((nfm_demod_settings != nullptr) && (nfm_demod_settings->isSet())){ toJsonValue(QString("NFMDemodSettings"), nfm_demod_settings, obj, QString("SWGNFMDemodSettings")); } @@ -957,6 +969,16 @@ SWGChannelSettings::setIeee802154ModSettings(SWGIEEE_802_15_4_ModSettings* ieee_ this->m_ieee_802_15_4_mod_settings_isSet = true; } +SWGM17DemodSettings* +SWGChannelSettings::getM17DemodSettings() { + return m17_demod_settings; +} +void +SWGChannelSettings::setM17DemodSettings(SWGM17DemodSettings* m17_demod_settings) { + this->m17_demod_settings = m17_demod_settings; + this->m_m17_demod_settings_isSet = true; +} + SWGNFMDemodSettings* SWGChannelSettings::getNfmDemodSettings() { return nfm_demod_settings; @@ -1259,6 +1281,9 @@ SWGChannelSettings::isSet(){ if(ieee_802_15_4_mod_settings && ieee_802_15_4_mod_settings->isSet()){ isObjectUpdated = true; break; } + if(m17_demod_settings && m17_demod_settings->isSet()){ + isObjectUpdated = true; break; + } if(nfm_demod_settings && nfm_demod_settings->isSet()){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h index a5411e9f6..fbbf7dc5b 100644 --- a/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGChannelSettings.h @@ -49,6 +49,7 @@ #include "SWGInterferometerSettings.h" #include "SWGLocalSinkSettings.h" #include "SWGLocalSourceSettings.h" +#include "SWGM17DemodSettings.h" #include "SWGNFMDemodSettings.h" #include "SWGNFMModSettings.h" #include "SWGNoiseFigureSettings.h" @@ -175,6 +176,9 @@ public: SWGIEEE_802_15_4_ModSettings* getIeee802154ModSettings(); void setIeee802154ModSettings(SWGIEEE_802_15_4_ModSettings* ieee_802_15_4_mod_settings); + SWGM17DemodSettings* getM17DemodSettings(); + void setM17DemodSettings(SWGM17DemodSettings* m17_demod_settings); + SWGNFMDemodSettings* getNfmDemodSettings(); void setNfmDemodSettings(SWGNFMDemodSettings* nfm_demod_settings); @@ -329,6 +333,9 @@ private: SWGIEEE_802_15_4_ModSettings* ieee_802_15_4_mod_settings; bool m_ieee_802_15_4_mod_settings_isSet; + SWGM17DemodSettings* m17_demod_settings; + bool m_m17_demod_settings_isSet; + SWGNFMDemodSettings* nfm_demod_settings; bool m_nfm_demod_settings_isSet; diff --git a/swagger/sdrangel/code/qt5/client/SWGM17DemodReport.cpp b/swagger/sdrangel/code/qt5/client/SWGM17DemodReport.cpp new file mode 100644 index 000000000..c07f8de9a --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGM17DemodReport.cpp @@ -0,0 +1,177 @@ +/** + * 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 "SWGM17DemodReport.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGM17DemodReport::SWGM17DemodReport(QString* json) { + init(); + this->fromJson(*json); +} + +SWGM17DemodReport::SWGM17DemodReport() { + channel_power_db = 0.0f; + m_channel_power_db_isSet = false; + audio_sample_rate = 0; + m_audio_sample_rate_isSet = false; + channel_sample_rate = 0; + m_channel_sample_rate_isSet = false; + squelch = 0; + m_squelch_isSet = false; +} + +SWGM17DemodReport::~SWGM17DemodReport() { + this->cleanup(); +} + +void +SWGM17DemodReport::init() { + channel_power_db = 0.0f; + m_channel_power_db_isSet = false; + audio_sample_rate = 0; + m_audio_sample_rate_isSet = false; + channel_sample_rate = 0; + m_channel_sample_rate_isSet = false; + squelch = 0; + m_squelch_isSet = false; +} + +void +SWGM17DemodReport::cleanup() { + + + + +} + +SWGM17DemodReport* +SWGM17DemodReport::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGM17DemodReport::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&channel_power_db, pJson["channelPowerDB"], "float", ""); + + ::SWGSDRangel::setValue(&audio_sample_rate, pJson["audioSampleRate"], "qint32", ""); + + ::SWGSDRangel::setValue(&channel_sample_rate, pJson["channelSampleRate"], "qint32", ""); + + ::SWGSDRangel::setValue(&squelch, pJson["squelch"], "qint32", ""); + +} + +QString +SWGM17DemodReport::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGM17DemodReport::asJsonObject() { + QJsonObject* obj = new QJsonObject(); + if(m_channel_power_db_isSet){ + obj->insert("channelPowerDB", QJsonValue(channel_power_db)); + } + if(m_audio_sample_rate_isSet){ + obj->insert("audioSampleRate", QJsonValue(audio_sample_rate)); + } + if(m_channel_sample_rate_isSet){ + obj->insert("channelSampleRate", QJsonValue(channel_sample_rate)); + } + if(m_squelch_isSet){ + obj->insert("squelch", QJsonValue(squelch)); + } + + return obj; +} + +float +SWGM17DemodReport::getChannelPowerDb() { + return channel_power_db; +} +void +SWGM17DemodReport::setChannelPowerDb(float channel_power_db) { + this->channel_power_db = channel_power_db; + this->m_channel_power_db_isSet = true; +} + +qint32 +SWGM17DemodReport::getAudioSampleRate() { + return audio_sample_rate; +} +void +SWGM17DemodReport::setAudioSampleRate(qint32 audio_sample_rate) { + this->audio_sample_rate = audio_sample_rate; + this->m_audio_sample_rate_isSet = true; +} + +qint32 +SWGM17DemodReport::getChannelSampleRate() { + return channel_sample_rate; +} +void +SWGM17DemodReport::setChannelSampleRate(qint32 channel_sample_rate) { + this->channel_sample_rate = channel_sample_rate; + this->m_channel_sample_rate_isSet = true; +} + +qint32 +SWGM17DemodReport::getSquelch() { + return squelch; +} +void +SWGM17DemodReport::setSquelch(qint32 squelch) { + this->squelch = squelch; + this->m_squelch_isSet = true; +} + + +bool +SWGM17DemodReport::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_channel_power_db_isSet){ + isObjectUpdated = true; break; + } + if(m_audio_sample_rate_isSet){ + isObjectUpdated = true; break; + } + if(m_channel_sample_rate_isSet){ + isObjectUpdated = true; break; + } + if(m_squelch_isSet){ + isObjectUpdated = true; break; + } + }while(false); + return isObjectUpdated; +} +} + diff --git a/swagger/sdrangel/code/qt5/client/SWGM17DemodReport.h b/swagger/sdrangel/code/qt5/client/SWGM17DemodReport.h new file mode 100644 index 000000000..bde2a4558 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGM17DemodReport.h @@ -0,0 +1,76 @@ +/** + * 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. + */ + +/* + * SWGM17DemodReport.h + * + * M17Demod + */ + +#ifndef SWGM17DemodReport_H_ +#define SWGM17DemodReport_H_ + +#include + + + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGM17DemodReport: public SWGObject { +public: + SWGM17DemodReport(); + SWGM17DemodReport(QString* json); + virtual ~SWGM17DemodReport(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGM17DemodReport* fromJson(QString &jsonString) override; + + float getChannelPowerDb(); + void setChannelPowerDb(float channel_power_db); + + qint32 getAudioSampleRate(); + void setAudioSampleRate(qint32 audio_sample_rate); + + qint32 getChannelSampleRate(); + void setChannelSampleRate(qint32 channel_sample_rate); + + qint32 getSquelch(); + void setSquelch(qint32 squelch); + + + virtual bool isSet() override; + +private: + float channel_power_db; + bool m_channel_power_db_isSet; + + qint32 audio_sample_rate; + bool m_audio_sample_rate_isSet; + + qint32 channel_sample_rate; + bool m_channel_sample_rate_isSet; + + qint32 squelch; + bool m_squelch_isSet; + +}; + +} + +#endif /* SWGM17DemodReport_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGM17DemodSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGM17DemodSettings.cpp new file mode 100644 index 000000000..a49b68f07 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGM17DemodSettings.cpp @@ -0,0 +1,693 @@ +/** + * 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 "SWGM17DemodSettings.h" + +#include "SWGHelpers.h" + +#include +#include +#include +#include + +namespace SWGSDRangel { + +SWGM17DemodSettings::SWGM17DemodSettings(QString* json) { + init(); + this->fromJson(*json); +} + +SWGM17DemodSettings::SWGM17DemodSettings() { + input_frequency_offset = 0L; + m_input_frequency_offset_isSet = false; + rf_bandwidth = 0.0f; + m_rf_bandwidth_isSet = false; + fm_deviation = 0.0f; + m_fm_deviation_isSet = false; + demod_gain = 0.0f; + m_demod_gain_isSet = false; + volume = 0.0f; + m_volume_isSet = false; + baud_rate = 0; + m_baud_rate_isSet = false; + squelch_gate = 0; + m_squelch_gate_isSet = false; + squelch = 0.0f; + m_squelch_isSet = false; + audio_mute = 0; + m_audio_mute_isSet = false; + sync_or_constellation = 0; + m_sync_or_constellation_isSet = false; + pll_lock = 0; + m_pll_lock_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + title = nullptr; + m_title_isSet = false; + audio_device_name = nullptr; + m_audio_device_name_isSet = false; + high_pass_filter = 0; + m_high_pass_filter_isSet = false; + trace_length_mutliplier = 0; + m_trace_length_mutliplier_isSet = false; + trace_stroke = 0; + m_trace_stroke_isSet = false; + trace_decay = 0; + m_trace_decay_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; +} + +SWGM17DemodSettings::~SWGM17DemodSettings() { + this->cleanup(); +} + +void +SWGM17DemodSettings::init() { + input_frequency_offset = 0L; + m_input_frequency_offset_isSet = false; + rf_bandwidth = 0.0f; + m_rf_bandwidth_isSet = false; + fm_deviation = 0.0f; + m_fm_deviation_isSet = false; + demod_gain = 0.0f; + m_demod_gain_isSet = false; + volume = 0.0f; + m_volume_isSet = false; + baud_rate = 0; + m_baud_rate_isSet = false; + squelch_gate = 0; + m_squelch_gate_isSet = false; + squelch = 0.0f; + m_squelch_isSet = false; + audio_mute = 0; + m_audio_mute_isSet = false; + sync_or_constellation = 0; + m_sync_or_constellation_isSet = false; + pll_lock = 0; + m_pll_lock_isSet = false; + rgb_color = 0; + m_rgb_color_isSet = false; + title = new QString(""); + m_title_isSet = false; + audio_device_name = new QString(""); + m_audio_device_name_isSet = false; + high_pass_filter = 0; + m_high_pass_filter_isSet = false; + trace_length_mutliplier = 0; + m_trace_length_mutliplier_isSet = false; + trace_stroke = 0; + m_trace_stroke_isSet = false; + trace_decay = 0; + m_trace_decay_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 +SWGM17DemodSettings::cleanup() { + + + + + + + + + + + + + if(title != nullptr) { + delete title; + } + if(audio_device_name != nullptr) { + delete audio_device_name; + } + + + + + + + if(reverse_api_address != nullptr) { + delete reverse_api_address; + } + + + + if(channel_marker != nullptr) { + delete channel_marker; + } + if(rollup_state != nullptr) { + delete rollup_state; + } +} + +SWGM17DemodSettings* +SWGM17DemodSettings::fromJson(QString &json) { + QByteArray array (json.toStdString().c_str()); + QJsonDocument doc = QJsonDocument::fromJson(array); + QJsonObject jsonObject = doc.object(); + this->fromJsonObject(jsonObject); + return this; +} + +void +SWGM17DemodSettings::fromJsonObject(QJsonObject &pJson) { + ::SWGSDRangel::setValue(&input_frequency_offset, pJson["inputFrequencyOffset"], "qint64", ""); + + ::SWGSDRangel::setValue(&rf_bandwidth, pJson["rfBandwidth"], "float", ""); + + ::SWGSDRangel::setValue(&fm_deviation, pJson["fmDeviation"], "float", ""); + + ::SWGSDRangel::setValue(&demod_gain, pJson["demodGain"], "float", ""); + + ::SWGSDRangel::setValue(&volume, pJson["volume"], "float", ""); + + ::SWGSDRangel::setValue(&baud_rate, pJson["baudRate"], "qint32", ""); + + ::SWGSDRangel::setValue(&squelch_gate, pJson["squelchGate"], "qint32", ""); + + ::SWGSDRangel::setValue(&squelch, pJson["squelch"], "float", ""); + + ::SWGSDRangel::setValue(&audio_mute, pJson["audioMute"], "qint32", ""); + + ::SWGSDRangel::setValue(&sync_or_constellation, pJson["syncOrConstellation"], "qint32", ""); + + ::SWGSDRangel::setValue(&pll_lock, pJson["pllLock"], "qint32", ""); + + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); + + ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); + + ::SWGSDRangel::setValue(&audio_device_name, pJson["audioDeviceName"], "QString", "QString"); + + ::SWGSDRangel::setValue(&high_pass_filter, pJson["highPassFilter"], "qint32", ""); + + ::SWGSDRangel::setValue(&trace_length_mutliplier, pJson["traceLengthMutliplier"], "qint32", ""); + + ::SWGSDRangel::setValue(&trace_stroke, pJson["traceStroke"], "qint32", ""); + + ::SWGSDRangel::setValue(&trace_decay, pJson["traceDecay"], "qint32", ""); + + ::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 +SWGM17DemodSettings::asJson () +{ + QJsonObject* obj = this->asJsonObject(); + + QJsonDocument doc(*obj); + QByteArray bytes = doc.toJson(); + delete obj; + return QString(bytes); +} + +QJsonObject* +SWGM17DemodSettings::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_fm_deviation_isSet){ + obj->insert("fmDeviation", QJsonValue(fm_deviation)); + } + if(m_demod_gain_isSet){ + obj->insert("demodGain", QJsonValue(demod_gain)); + } + if(m_volume_isSet){ + obj->insert("volume", QJsonValue(volume)); + } + if(m_baud_rate_isSet){ + obj->insert("baudRate", QJsonValue(baud_rate)); + } + if(m_squelch_gate_isSet){ + obj->insert("squelchGate", QJsonValue(squelch_gate)); + } + if(m_squelch_isSet){ + obj->insert("squelch", QJsonValue(squelch)); + } + if(m_audio_mute_isSet){ + obj->insert("audioMute", QJsonValue(audio_mute)); + } + if(m_sync_or_constellation_isSet){ + obj->insert("syncOrConstellation", QJsonValue(sync_or_constellation)); + } + if(m_pll_lock_isSet){ + obj->insert("pllLock", QJsonValue(pll_lock)); + } + if(m_rgb_color_isSet){ + obj->insert("rgbColor", QJsonValue(rgb_color)); + } + if(title != nullptr && *title != QString("")){ + toJsonValue(QString("title"), title, obj, QString("QString")); + } + if(audio_device_name != nullptr && *audio_device_name != QString("")){ + toJsonValue(QString("audioDeviceName"), audio_device_name, obj, QString("QString")); + } + if(m_high_pass_filter_isSet){ + obj->insert("highPassFilter", QJsonValue(high_pass_filter)); + } + if(m_trace_length_mutliplier_isSet){ + obj->insert("traceLengthMutliplier", QJsonValue(trace_length_mutliplier)); + } + if(m_trace_stroke_isSet){ + obj->insert("traceStroke", QJsonValue(trace_stroke)); + } + if(m_trace_decay_isSet){ + obj->insert("traceDecay", QJsonValue(trace_decay)); + } + 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 +SWGM17DemodSettings::getInputFrequencyOffset() { + return input_frequency_offset; +} +void +SWGM17DemodSettings::setInputFrequencyOffset(qint64 input_frequency_offset) { + this->input_frequency_offset = input_frequency_offset; + this->m_input_frequency_offset_isSet = true; +} + +float +SWGM17DemodSettings::getRfBandwidth() { + return rf_bandwidth; +} +void +SWGM17DemodSettings::setRfBandwidth(float rf_bandwidth) { + this->rf_bandwidth = rf_bandwidth; + this->m_rf_bandwidth_isSet = true; +} + +float +SWGM17DemodSettings::getFmDeviation() { + return fm_deviation; +} +void +SWGM17DemodSettings::setFmDeviation(float fm_deviation) { + this->fm_deviation = fm_deviation; + this->m_fm_deviation_isSet = true; +} + +float +SWGM17DemodSettings::getDemodGain() { + return demod_gain; +} +void +SWGM17DemodSettings::setDemodGain(float demod_gain) { + this->demod_gain = demod_gain; + this->m_demod_gain_isSet = true; +} + +float +SWGM17DemodSettings::getVolume() { + return volume; +} +void +SWGM17DemodSettings::setVolume(float volume) { + this->volume = volume; + this->m_volume_isSet = true; +} + +qint32 +SWGM17DemodSettings::getBaudRate() { + return baud_rate; +} +void +SWGM17DemodSettings::setBaudRate(qint32 baud_rate) { + this->baud_rate = baud_rate; + this->m_baud_rate_isSet = true; +} + +qint32 +SWGM17DemodSettings::getSquelchGate() { + return squelch_gate; +} +void +SWGM17DemodSettings::setSquelchGate(qint32 squelch_gate) { + this->squelch_gate = squelch_gate; + this->m_squelch_gate_isSet = true; +} + +float +SWGM17DemodSettings::getSquelch() { + return squelch; +} +void +SWGM17DemodSettings::setSquelch(float squelch) { + this->squelch = squelch; + this->m_squelch_isSet = true; +} + +qint32 +SWGM17DemodSettings::getAudioMute() { + return audio_mute; +} +void +SWGM17DemodSettings::setAudioMute(qint32 audio_mute) { + this->audio_mute = audio_mute; + this->m_audio_mute_isSet = true; +} + +qint32 +SWGM17DemodSettings::getSyncOrConstellation() { + return sync_or_constellation; +} +void +SWGM17DemodSettings::setSyncOrConstellation(qint32 sync_or_constellation) { + this->sync_or_constellation = sync_or_constellation; + this->m_sync_or_constellation_isSet = true; +} + +qint32 +SWGM17DemodSettings::getPllLock() { + return pll_lock; +} +void +SWGM17DemodSettings::setPllLock(qint32 pll_lock) { + this->pll_lock = pll_lock; + this->m_pll_lock_isSet = true; +} + +qint32 +SWGM17DemodSettings::getRgbColor() { + return rgb_color; +} +void +SWGM17DemodSettings::setRgbColor(qint32 rgb_color) { + this->rgb_color = rgb_color; + this->m_rgb_color_isSet = true; +} + +QString* +SWGM17DemodSettings::getTitle() { + return title; +} +void +SWGM17DemodSettings::setTitle(QString* title) { + this->title = title; + this->m_title_isSet = true; +} + +QString* +SWGM17DemodSettings::getAudioDeviceName() { + return audio_device_name; +} +void +SWGM17DemodSettings::setAudioDeviceName(QString* audio_device_name) { + this->audio_device_name = audio_device_name; + this->m_audio_device_name_isSet = true; +} + +qint32 +SWGM17DemodSettings::getHighPassFilter() { + return high_pass_filter; +} +void +SWGM17DemodSettings::setHighPassFilter(qint32 high_pass_filter) { + this->high_pass_filter = high_pass_filter; + this->m_high_pass_filter_isSet = true; +} + +qint32 +SWGM17DemodSettings::getTraceLengthMutliplier() { + return trace_length_mutliplier; +} +void +SWGM17DemodSettings::setTraceLengthMutliplier(qint32 trace_length_mutliplier) { + this->trace_length_mutliplier = trace_length_mutliplier; + this->m_trace_length_mutliplier_isSet = true; +} + +qint32 +SWGM17DemodSettings::getTraceStroke() { + return trace_stroke; +} +void +SWGM17DemodSettings::setTraceStroke(qint32 trace_stroke) { + this->trace_stroke = trace_stroke; + this->m_trace_stroke_isSet = true; +} + +qint32 +SWGM17DemodSettings::getTraceDecay() { + return trace_decay; +} +void +SWGM17DemodSettings::setTraceDecay(qint32 trace_decay) { + this->trace_decay = trace_decay; + this->m_trace_decay_isSet = true; +} + +qint32 +SWGM17DemodSettings::getStreamIndex() { + return stream_index; +} +void +SWGM17DemodSettings::setStreamIndex(qint32 stream_index) { + this->stream_index = stream_index; + this->m_stream_index_isSet = true; +} + +qint32 +SWGM17DemodSettings::getUseReverseApi() { + return use_reverse_api; +} +void +SWGM17DemodSettings::setUseReverseApi(qint32 use_reverse_api) { + this->use_reverse_api = use_reverse_api; + this->m_use_reverse_api_isSet = true; +} + +QString* +SWGM17DemodSettings::getReverseApiAddress() { + return reverse_api_address; +} +void +SWGM17DemodSettings::setReverseApiAddress(QString* reverse_api_address) { + this->reverse_api_address = reverse_api_address; + this->m_reverse_api_address_isSet = true; +} + +qint32 +SWGM17DemodSettings::getReverseApiPort() { + return reverse_api_port; +} +void +SWGM17DemodSettings::setReverseApiPort(qint32 reverse_api_port) { + this->reverse_api_port = reverse_api_port; + this->m_reverse_api_port_isSet = true; +} + +qint32 +SWGM17DemodSettings::getReverseApiDeviceIndex() { + return reverse_api_device_index; +} +void +SWGM17DemodSettings::setReverseApiDeviceIndex(qint32 reverse_api_device_index) { + this->reverse_api_device_index = reverse_api_device_index; + this->m_reverse_api_device_index_isSet = true; +} + +qint32 +SWGM17DemodSettings::getReverseApiChannelIndex() { + return reverse_api_channel_index; +} +void +SWGM17DemodSettings::setReverseApiChannelIndex(qint32 reverse_api_channel_index) { + this->reverse_api_channel_index = reverse_api_channel_index; + this->m_reverse_api_channel_index_isSet = true; +} + +SWGChannelMarker* +SWGM17DemodSettings::getChannelMarker() { + return channel_marker; +} +void +SWGM17DemodSettings::setChannelMarker(SWGChannelMarker* channel_marker) { + this->channel_marker = channel_marker; + this->m_channel_marker_isSet = true; +} + +SWGRollupState* +SWGM17DemodSettings::getRollupState() { + return rollup_state; +} +void +SWGM17DemodSettings::setRollupState(SWGRollupState* rollup_state) { + this->rollup_state = rollup_state; + this->m_rollup_state_isSet = true; +} + + +bool +SWGM17DemodSettings::isSet(){ + bool isObjectUpdated = false; + do{ + if(m_input_frequency_offset_isSet){ + isObjectUpdated = true; break; + } + if(m_rf_bandwidth_isSet){ + isObjectUpdated = true; break; + } + if(m_fm_deviation_isSet){ + isObjectUpdated = true; break; + } + if(m_demod_gain_isSet){ + isObjectUpdated = true; break; + } + if(m_volume_isSet){ + isObjectUpdated = true; break; + } + if(m_baud_rate_isSet){ + isObjectUpdated = true; break; + } + if(m_squelch_gate_isSet){ + isObjectUpdated = true; break; + } + if(m_squelch_isSet){ + isObjectUpdated = true; break; + } + if(m_audio_mute_isSet){ + isObjectUpdated = true; break; + } + if(m_sync_or_constellation_isSet){ + isObjectUpdated = true; break; + } + if(m_pll_lock_isSet){ + isObjectUpdated = true; break; + } + if(m_rgb_color_isSet){ + isObjectUpdated = true; break; + } + if(title && *title != QString("")){ + isObjectUpdated = true; break; + } + if(audio_device_name && *audio_device_name != QString("")){ + isObjectUpdated = true; break; + } + if(m_high_pass_filter_isSet){ + isObjectUpdated = true; break; + } + if(m_trace_length_mutliplier_isSet){ + isObjectUpdated = true; break; + } + if(m_trace_stroke_isSet){ + isObjectUpdated = true; break; + } + if(m_trace_decay_isSet){ + 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/SWGM17DemodSettings.h b/swagger/sdrangel/code/qt5/client/SWGM17DemodSettings.h new file mode 100644 index 000000000..dcb2d1059 --- /dev/null +++ b/swagger/sdrangel/code/qt5/client/SWGM17DemodSettings.h @@ -0,0 +1,211 @@ +/** + * 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. + */ + +/* + * SWGM17DemodSettings.h + * + * M17Demod + */ + +#ifndef SWGM17DemodSettings_H_ +#define SWGM17DemodSettings_H_ + +#include + + +#include "SWGChannelMarker.h" +#include "SWGRollupState.h" +#include + +#include "SWGObject.h" +#include "export.h" + +namespace SWGSDRangel { + +class SWG_API SWGM17DemodSettings: public SWGObject { +public: + SWGM17DemodSettings(); + SWGM17DemodSettings(QString* json); + virtual ~SWGM17DemodSettings(); + void init(); + void cleanup(); + + virtual QString asJson () override; + virtual QJsonObject* asJsonObject() override; + virtual void fromJsonObject(QJsonObject &json) override; + virtual SWGM17DemodSettings* fromJson(QString &jsonString) override; + + qint64 getInputFrequencyOffset(); + void setInputFrequencyOffset(qint64 input_frequency_offset); + + float getRfBandwidth(); + void setRfBandwidth(float rf_bandwidth); + + float getFmDeviation(); + void setFmDeviation(float fm_deviation); + + float getDemodGain(); + void setDemodGain(float demod_gain); + + float getVolume(); + void setVolume(float volume); + + qint32 getBaudRate(); + void setBaudRate(qint32 baud_rate); + + qint32 getSquelchGate(); + void setSquelchGate(qint32 squelch_gate); + + float getSquelch(); + void setSquelch(float squelch); + + qint32 getAudioMute(); + void setAudioMute(qint32 audio_mute); + + qint32 getSyncOrConstellation(); + void setSyncOrConstellation(qint32 sync_or_constellation); + + qint32 getPllLock(); + void setPllLock(qint32 pll_lock); + + qint32 getRgbColor(); + void setRgbColor(qint32 rgb_color); + + QString* getTitle(); + void setTitle(QString* title); + + QString* getAudioDeviceName(); + void setAudioDeviceName(QString* audio_device_name); + + qint32 getHighPassFilter(); + void setHighPassFilter(qint32 high_pass_filter); + + qint32 getTraceLengthMutliplier(); + void setTraceLengthMutliplier(qint32 trace_length_mutliplier); + + qint32 getTraceStroke(); + void setTraceStroke(qint32 trace_stroke); + + qint32 getTraceDecay(); + void setTraceDecay(qint32 trace_decay); + + 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; + + float rf_bandwidth; + bool m_rf_bandwidth_isSet; + + float fm_deviation; + bool m_fm_deviation_isSet; + + float demod_gain; + bool m_demod_gain_isSet; + + float volume; + bool m_volume_isSet; + + qint32 baud_rate; + bool m_baud_rate_isSet; + + qint32 squelch_gate; + bool m_squelch_gate_isSet; + + float squelch; + bool m_squelch_isSet; + + qint32 audio_mute; + bool m_audio_mute_isSet; + + qint32 sync_or_constellation; + bool m_sync_or_constellation_isSet; + + qint32 pll_lock; + bool m_pll_lock_isSet; + + qint32 rgb_color; + bool m_rgb_color_isSet; + + QString* title; + bool m_title_isSet; + + QString* audio_device_name; + bool m_audio_device_name_isSet; + + qint32 high_pass_filter; + bool m_high_pass_filter_isSet; + + qint32 trace_length_mutliplier; + bool m_trace_length_mutliplier_isSet; + + qint32 trace_stroke; + bool m_trace_stroke_isSet; + + qint32 trace_decay; + bool m_trace_decay_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 /* SWGM17DemodSettings_H_ */ diff --git a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h index d6891d140..ac6e46663 100644 --- a/swagger/sdrangel/code/qt5/client/SWGModelFactory.h +++ b/swagger/sdrangel/code/qt5/client/SWGModelFactory.h @@ -183,6 +183,8 @@ #include "SWGLocalSourceSettings.h" #include "SWGLocationInformation.h" #include "SWGLoggingInfo.h" +#include "SWGM17DemodReport.h" +#include "SWGM17DemodSettings.h" #include "SWGMapActions.h" #include "SWGMapAnimation.h" #include "SWGMapCoordinate.h" @@ -1180,6 +1182,16 @@ namespace SWGSDRangel { obj->init(); return obj; } + if(QString("SWGM17DemodReport").compare(type) == 0) { + SWGM17DemodReport *obj = new SWGM17DemodReport(); + obj->init(); + return obj; + } + if(QString("SWGM17DemodSettings").compare(type) == 0) { + SWGM17DemodSettings *obj = new SWGM17DemodSettings(); + obj->init(); + return obj; + } if(QString("SWGMapActions").compare(type) == 0) { SWGMapActions *obj = new SWGMapActions(); obj->init();