diff --git a/plugins/channeltx/modam/ammod.cpp b/plugins/channeltx/modam/ammod.cpp index 81f21c521..4992632e2 100644 --- a/plugins/channeltx/modam/ammod.cpp +++ b/plugins/channeltx/modam/ammod.cpp @@ -511,7 +511,6 @@ bool AMMod::deserialize(const QByteArray& data) } } - int AMMod::webapiSettingsGet( SWGSDRangel::SWGChannelSettings& response, QString& errorMessage __attribute__((unused))) @@ -542,6 +541,9 @@ int AMMod::webapiSettingsPutPatch( if (channelSettingsKeys.contains("modAFInput")) { settings.m_modAFInput = (AMModSettings::AMModInputAF) response.getAmModSettings()->getModAfInput(); } + if (channelSettingsKeys.contains("audioDeviceName")) { + settings.m_audioDeviceName = *response.getAmModSettings()->getAudioDeviceName(); + } if (channelSettingsKeys.contains("playLoop")) { settings.m_playLoop = response.getAmModSettings()->getPlayLoop() != 0; } diff --git a/plugins/channeltx/modssb/CMakeLists.txt b/plugins/channeltx/modssb/CMakeLists.txt index b8650ad5b..631900497 100644 --- a/plugins/channeltx/modssb/CMakeLists.txt +++ b/plugins/channeltx/modssb/CMakeLists.txt @@ -23,6 +23,7 @@ set(modssb_FORMS include_directories( . ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client ) add_definitions(${QT_DEFINITIONS}) @@ -41,6 +42,7 @@ target_link_libraries(modssb ${QT_LIBRARIES} sdrbase sdrgui + swagger ) qt5_use_modules(modssb Core Widgets) diff --git a/plugins/channeltx/modssb/ssbmod.cpp b/plugins/channeltx/modssb/ssbmod.cpp index ba5223b17..8c341e4be 100644 --- a/plugins/channeltx/modssb/ssbmod.cpp +++ b/plugins/channeltx/modssb/ssbmod.cpp @@ -23,6 +23,10 @@ #include #include +#include "SWGChannelSettings.h" +#include "SWGChannelReport.h" +#include "SWGSSBModReport.h" + #include "dsp/upchannelizer.h" #include "dsp/dspengine.h" #include "dsp/threadedbasebandsamplesource.h" @@ -866,3 +870,223 @@ bool SSBMod::deserialize(const QByteArray& data) return false; } } + +int SSBMod::webapiSettingsGet( + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage __attribute__((unused))) +{ + response.setSsbModSettings(new SWGSDRangel::SWGSSBModSettings()); + response.getSsbModSettings()->init(); + webapiFormatChannelSettings(response, m_settings); + return 200; +} + +int SSBMod::webapiSettingsPutPatch( + bool force, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage __attribute__((unused))) +{ + SSBModSettings settings; + bool frequencyOffsetChanged = false; + + if (channelSettingsKeys.contains("inputFrequencyOffset")) + { + settings.m_inputFrequencyOffset = response.getSsbModSettings()->getInputFrequencyOffset(); + frequencyOffsetChanged = true; + } + if (channelSettingsKeys.contains("bandwidth")) { + settings.m_bandwidth = response.getSsbModSettings()->getBandwidth(); + } + if (channelSettingsKeys.contains("lowCutoff")) { + settings.m_lowCutoff = response.getSsbModSettings()->getLowCutoff(); + } + if (channelSettingsKeys.contains("usb")) { + settings.m_usb = response.getSsbModSettings()->getUsb() != 0; + } + if (channelSettingsKeys.contains("toneFrequency")) { + settings.m_toneFrequency = response.getSsbModSettings()->getToneFrequency(); + } + if (channelSettingsKeys.contains("volumeFactor")) { + settings.m_volumeFactor = response.getSsbModSettings()->getVolumeFactor(); + } + if (channelSettingsKeys.contains("spanLog2")) { + settings.m_spanLog2 = response.getSsbModSettings()->getSpanLog2(); + } + if (channelSettingsKeys.contains("audioBinaural")) { + settings.m_audioBinaural = response.getSsbModSettings()->getAudioBinaural() != 0; + } + if (channelSettingsKeys.contains("audioFlipChannels")) { + settings.m_audioFlipChannels = response.getSsbModSettings()->getAudioFlipChannels() != 0; + } + if (channelSettingsKeys.contains("dsb")) { + settings.m_dsb = response.getSsbModSettings()->getDsb() != 0; + } + if (channelSettingsKeys.contains("audioMute")) { + settings.m_audioMute = response.getSsbModSettings()->getAudioMute() != 0; + } + if (channelSettingsKeys.contains("playLoop")) { + settings.m_playLoop = response.getSsbModSettings()->getPlayLoop() != 0; + } + if (channelSettingsKeys.contains("agc")) { + settings.m_agc = response.getSsbModSettings()->getAgc() != 0; + } + if (channelSettingsKeys.contains("agcOrder")) { + settings.m_agcOrder = response.getSsbModSettings()->getAgcOrder(); + } + if (channelSettingsKeys.contains("agcTime")) { + settings.m_agcTime = response.getSsbModSettings()->getAgcTime(); + } + if (channelSettingsKeys.contains("agcThresholdEnable")) { + settings.m_agcThresholdEnable = response.getSsbModSettings()->getAgcThresholdEnable() != 0; + } + if (channelSettingsKeys.contains("agcThreshold")) { + settings.m_agcThreshold = response.getSsbModSettings()->getAgcThreshold(); + } + if (channelSettingsKeys.contains("agcThresholdGate")) { + settings.m_agcThresholdGate = response.getSsbModSettings()->getAgcThresholdGate(); + } + if (channelSettingsKeys.contains("agcThresholdDelay")) { + settings.m_agcThresholdDelay = response.getSsbModSettings()->getAgcThresholdDelay(); + } + if (channelSettingsKeys.contains("rgbColor")) { + settings.m_rgbColor = response.getSsbModSettings()->getRgbColor(); + } + if (channelSettingsKeys.contains("title")) { + settings.m_title = *response.getSsbModSettings()->getTitle(); + } + if (channelSettingsKeys.contains("modAFInput")) { + settings.m_modAFInput = (SSBModSettings::SSBModInputAF) response.getSsbModSettings()->getModAfInput(); + } + if (channelSettingsKeys.contains("audioDeviceName")) { + settings.m_audioDeviceName = *response.getSsbModSettings()->getAudioDeviceName(); + } + + if (channelSettingsKeys.contains("cwKeyer")) + { + SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getSsbModSettings()->getCwKeyer(); + CWKeyerSettings cwKeyerSettings = m_cwKeyer.getSettings(); + + if (channelSettingsKeys.contains("cwKeyer.loop")) { + cwKeyerSettings.m_loop = apiCwKeyerSettings->getLoop() != 0; + } + if (channelSettingsKeys.contains("cwKeyer.mode")) { + cwKeyerSettings.m_mode = (CWKeyerSettings::CWMode) apiCwKeyerSettings->getMode(); + } + if (channelSettingsKeys.contains("cwKeyer.text")) { + cwKeyerSettings.m_text = *apiCwKeyerSettings->getText(); + } + if (channelSettingsKeys.contains("cwKeyer.sampleRate")) { + cwKeyerSettings.m_sampleRate = apiCwKeyerSettings->getSampleRate(); + } + if (channelSettingsKeys.contains("cwKeyer.wpm")) { + cwKeyerSettings.m_wpm = apiCwKeyerSettings->getWpm(); + } + + m_cwKeyer.setLoop(cwKeyerSettings.m_loop); + m_cwKeyer.setMode(cwKeyerSettings.m_mode); + m_cwKeyer.setSampleRate(cwKeyerSettings.m_sampleRate); + m_cwKeyer.setText(cwKeyerSettings.m_text); + m_cwKeyer.setWPM(cwKeyerSettings.m_wpm); + + if (m_guiMessageQueue) // forward to GUI if any + { + CWKeyer::MsgConfigureCWKeyer *msgCwKeyer = CWKeyer::MsgConfigureCWKeyer::create(cwKeyerSettings, force); + m_guiMessageQueue->push(msgCwKeyer); + } + } + + if (frequencyOffsetChanged) + { + SSBMod::MsgConfigureChannelizer *msgChan = SSBMod::MsgConfigureChannelizer::create( + m_audioSampleRate, settings.m_inputFrequencyOffset); + m_inputMessageQueue.push(msgChan); + } + + MsgConfigureSSBMod *msg = MsgConfigureSSBMod::create(settings, force); + m_inputMessageQueue.push(msg); + + if (m_guiMessageQueue) // forward to GUI if any + { + MsgConfigureSSBMod *msgToGUI = MsgConfigureSSBMod::create(settings, force); + m_guiMessageQueue->push(msgToGUI); + } + + webapiFormatChannelSettings(response, settings); + + return 200; +} + +int SSBMod::webapiReportGet( + SWGSDRangel::SWGChannelReport& response, + QString& errorMessage __attribute__((unused))) +{ + response.setSsbModReport(new SWGSDRangel::SWGSSBModReport()); + response.getSsbModReport()->init(); + webapiFormatChannelReport(response); + return 200; +} + +void SSBMod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const SSBModSettings& settings) +{ + response.getSsbModSettings()->setInputFrequencyOffset(settings.m_inputFrequencyOffset); + response.getSsbModSettings()->setBandwidth(settings.m_bandwidth); + response.getSsbModSettings()->setLowCutoff(settings.m_lowCutoff); + response.getSsbModSettings()->setUsb(settings.m_usb ? 1 : 0); + response.getSsbModSettings()->setToneFrequency(settings.m_toneFrequency); + response.getSsbModSettings()->setVolumeFactor(settings.m_volumeFactor); + response.getSsbModSettings()->setSpanLog2(settings.m_spanLog2); + response.getSsbModSettings()->setAudioBinaural(settings.m_audioBinaural ? 1 : 0); + response.getSsbModSettings()->setAudioFlipChannels(settings.m_audioFlipChannels ? 1 : 0); + response.getSsbModSettings()->setDsb(settings.m_dsb ? 1 : 0); + response.getSsbModSettings()->setAudioMute(settings.m_audioMute ? 1 : 0); + response.getSsbModSettings()->setPlayLoop(settings.m_playLoop ? 1 : 0); + response.getSsbModSettings()->setAgc(settings.m_agc ? 1 : 0); + response.getSsbModSettings()->setAgcOrder(settings.m_agcOrder); + response.getSsbModSettings()->setAgcTime(settings.m_agcTime); + response.getSsbModSettings()->setAgcThresholdEnable(settings.m_agcThresholdEnable ? 1 : 0); + response.getSsbModSettings()->setAgcThreshold(settings.m_agcThreshold); + response.getSsbModSettings()->setAgcThresholdGate(settings.m_agcThresholdGate); + response.getSsbModSettings()->setAgcThresholdDelay(settings.m_agcThresholdDelay); + response.getSsbModSettings()->setRgbColor(settings.m_rgbColor); + + if (response.getSsbModSettings()->getTitle()) { + *response.getSsbModSettings()->getTitle() = settings.m_title; + } else { + response.getSsbModSettings()->setTitle(new QString(settings.m_title)); + } + + response.getSsbModSettings()->setModAfInput((int) settings.m_modAFInput); + + if (response.getSsbModSettings()->getAudioDeviceName()) { + *response.getSsbModSettings()->getAudioDeviceName() = settings.m_audioDeviceName; + } else { + response.getSsbModSettings()->setAudioDeviceName(new QString(settings.m_audioDeviceName)); + } + + if (!response.getSsbModSettings()->getCwKeyer()) { + response.getSsbModSettings()->setCwKeyer(new SWGSDRangel::SWGCWKeyerSettings); + } + + SWGSDRangel::SWGCWKeyerSettings *apiCwKeyerSettings = response.getSsbModSettings()->getCwKeyer(); + const CWKeyerSettings& cwKeyerSettings = m_cwKeyer.getSettings(); + apiCwKeyerSettings->setLoop(cwKeyerSettings.m_loop ? 1 : 0); + apiCwKeyerSettings->setMode((int) cwKeyerSettings.m_mode); + apiCwKeyerSettings->setSampleRate(cwKeyerSettings.m_sampleRate); + + if (apiCwKeyerSettings->getText()) { + *apiCwKeyerSettings->getText() = cwKeyerSettings.m_text; + } else { + apiCwKeyerSettings->setText(new QString(cwKeyerSettings.m_text)); + } + + apiCwKeyerSettings->setWpm(cwKeyerSettings.m_wpm); +} + +void SSBMod::webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response) +{ + response.getSsbModReport()->setChannelPowerDb(CalcDb::dbPower(getMagSq())); + response.getSsbModReport()->setAudioSampleRate(m_audioSampleRate); + response.getSsbModReport()->setChannelSampleRate(m_outputSampleRate); +} + diff --git a/plugins/channeltx/modssb/ssbmod.h b/plugins/channeltx/modssb/ssbmod.h index 5ce20caf3..4276f3b30 100644 --- a/plugins/channeltx/modssb/ssbmod.h +++ b/plugins/channeltx/modssb/ssbmod.h @@ -218,6 +218,20 @@ public: virtual QByteArray serialize() const; virtual bool deserialize(const QByteArray& data); + virtual int webapiSettingsGet( + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage); + + virtual int webapiSettingsPutPatch( + bool force, + const QStringList& channelSettingsKeys, + SWGSDRangel::SWGChannelSettings& response, + QString& errorMessage); + + virtual int webapiReportGet( + SWGSDRangel::SWGChannelReport& response, + QString& errorMessage); + uint32_t getAudioSampleRate() const { return m_audioSampleRate; } double getMagSq() const { return m_magsq; } @@ -306,6 +320,8 @@ private: void modulateSample(); void openFileStream(); void seekFileStream(int seekPercentage); + void webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& response, const SSBModSettings& settings); + void webapiFormatChannelReport(SWGSDRangel::SWGChannelReport& response); }; diff --git a/plugins/channeltx/modssb/ssbmodgui.cpp b/plugins/channeltx/modssb/ssbmodgui.cpp index 38990c54c..cfe276cc8 100644 --- a/plugins/channeltx/modssb/ssbmodgui.cpp +++ b/plugins/channeltx/modssb/ssbmodgui.cpp @@ -117,6 +117,21 @@ bool SSBModGUI::handleMessage(const Message& message) applyBandwidths(); // will update spectrum details with new sample rate return true; } + else if (SSBMod::MsgConfigureSSBMod::match(message)) + { + const SSBMod::MsgConfigureSSBMod& cfg = (SSBMod::MsgConfigureSSBMod&) message; + m_settings = cfg.getSettings(); + blockApplySettings(true); + displaySettings(); + blockApplySettings(false); + return true; + } + else if (CWKeyer::MsgConfigureCWKeyer::match(message)) + { + const CWKeyer::MsgConfigureCWKeyer& cfg = (CWKeyer::MsgConfigureCWKeyer&) message; + ui->cwKeyerGUI->displaySettings(cfg.getSettings()); + return true; + } else { return false; diff --git a/sdrbase/webapi/webapirequestmapper.cpp b/sdrbase/webapi/webapirequestmapper.cpp index be9e4c99d..48e6e3b41 100644 --- a/sdrbase/webapi/webapirequestmapper.cpp +++ b/sdrbase/webapi/webapirequestmapper.cpp @@ -1896,6 +1896,27 @@ bool WebAPIRequestMapper::validateChannelSettings( return false; } } + else if (*channelType == "SSBMod") + { + if (channelSettings.getTx() != 0) + { + QJsonObject ssbModSettingsJsonObject = jsonObject["SSBModSettings"].toObject(); + channelSettingsKeys = ssbModSettingsJsonObject.keys(); + + if (channelSettingsKeys.contains("cwKeyer")) + { + QJsonObject cwKeyerSettingsJsonObject; + appendSettingsSubKeys(ssbModSettingsJsonObject, cwKeyerSettingsJsonObject, "cwKeyer", channelSettingsKeys); + } + + channelSettings.setSsbModSettings(new SWGSDRangel::SWGSSBModSettings()); + channelSettings.getSsbModSettings()->fromJsonObject(ssbModSettingsJsonObject); + return true; + } + else { + return false; + } + } else if (*channelType == "WFMMod") { if (channelSettings.getTx() != 0) @@ -1998,6 +2019,20 @@ bool WebAPIRequestMapper::validateChannelReport( return false; } } + else if (*channelType == "SSBMod") + { + if (channelReport.getTx() != 0) + { + QJsonObject ssbModReportJsonObject = jsonObject["SSBModReport"].toObject(); + channelReportKeys = ssbModReportJsonObject.keys(); + channelReport.setSsbModReport(new SWGSDRangel::SWGSSBModReport()); + channelReport.getSsbModReport()->fromJsonObject(ssbModReportJsonObject); + return true; + } + else { + return false; + } + } else if (*channelType == "WFMMod") { if (channelReport.getTx() != 0) diff --git a/swagger/sdrangel/examples/tx_test.py b/swagger/sdrangel/examples/tx_test.py index 56ea228b2..f0ac3a4db 100644 --- a/swagger/sdrangel/examples/tx_test.py +++ b/swagger/sdrangel/examples/tx_test.py @@ -162,6 +162,16 @@ def setupChannel(options): settings["AMModSettings"]["toneFrequency"] = 600 settings["AMModSettings"]["modFactor"] = 0.9 settings["AMModSettings"]["rfBandwidth"] = 7500 + elif options.channel_id == "SSBMod": + settings["SSBModSettings"]["title"] = "Test SSB" + settings["SSBModSettings"]["inputFrequencyOffset"] = options.channel_freq + settings["SSBModSettings"]["cwKeyer"]["text"] = "VVV DE F4EXB " + settings["SSBModSettings"]["cwKeyer"]["loop"] = 1 + settings["SSBModSettings"]["cwKeyer"]["mode"] = 1 # text + settings["SSBModSettings"]["modAFInput"] = 4 # CW text + settings["SSBModSettings"]["toneFrequency"] = 600 + settings["SSBModSettings"]["bandwidth"] = 1000 + settings["SSBModSettings"]["lowCut"] = 300 elif options.channel_id == "WFMMod": settings["WFMModSettings"]["title"] = "Test WFM" settings["WFMModSettings"]["inputFrequencyOffset"] = options.channel_freq