From b1cf15213c2a75165c2ced02a030b1c265818236 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 19 Jan 2023 23:51:43 +0100 Subject: [PATCH] FT8 demod: implemented decoder --- ft8/CMakeLists.txt | 3 + ft8/unpack.cpp | 109 ++++--- ft8/unpack.h | 6 +- plugins/channelrx/demodft8/CMakeLists.txt | 2 + plugins/channelrx/demodft8/ft8demod.cpp | 40 +++ .../channelrx/demodft8/ft8demodbaseband.cpp | 27 +- plugins/channelrx/demodft8/ft8demodgui.cpp | 60 ++++ plugins/channelrx/demodft8/ft8demodgui.h | 19 ++ plugins/channelrx/demodft8/ft8demodgui.ui | 298 +++++++++++++++++- .../channelrx/demodft8/ft8demodsettings.cpp | 12 + plugins/channelrx/demodft8/ft8demodsettings.h | 5 +- plugins/channelrx/demodft8/ft8demodworker.cpp | 141 ++++++++- plugins/channelrx/demodft8/ft8demodworker.h | 48 +++ sdrbase/CMakeLists.txt | 2 + sdrbase/resources/webapi/doc/html2/index.html | 18 +- .../webapi/doc/swagger/include/FT8Demod.yaml | 19 ++ sdrbase/util/ft8message.cpp | 20 ++ sdrbase/util/ft8message.h | 58 ++++ .../api/swagger/include/FT8Demod.yaml | 19 ++ swagger/sdrangel/code/html2/index.html | 18 +- .../code/qt5/client/SWGFT8DemodSettings.cpp | 92 ++++++ .../code/qt5/client/SWGFT8DemodSettings.h | 24 ++ 22 files changed, 968 insertions(+), 72 deletions(-) create mode 100644 sdrbase/util/ft8message.cpp create mode 100644 sdrbase/util/ft8message.h diff --git a/ft8/CMakeLists.txt b/ft8/CMakeLists.txt index 41023a3b1..494750f51 100644 --- a/ft8/CMakeLists.txt +++ b/ft8/CMakeLists.txt @@ -37,4 +37,7 @@ target_link_libraries(ft8 sdrbase ) +# remove or comment when debugging is done +# set_property(TARGET ft8 PROPERTY COMPILE_OPTIONS "$<$:-Og>") + install(TARGETS ft8 DESTINATION ${INSTALL_LIB_DIR}) diff --git a/ft8/unpack.cpp b/ft8/unpack.cpp index 37586e620..fbc67f252 100644 --- a/ft8/unpack.cpp +++ b/ft8/unpack.cpp @@ -27,19 +27,17 @@ namespace FT8 { -int Packing::ihashcall(std::string call, int m) +int Packing::ihashcall(std::string rawcall, int m) { - while (call.size() > 0 && call[0] == ' ') - call.erase(0, 1); - while (call.size() > 0 && call[call.size() - 1] == ' ') - call.erase(call.end() - 1); - + std::string call = trim(rawcall); const char *chars = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/"; - while (call.size() < 11) + while (call.size() < 11) { call += " "; + } unsigned long long x = 0; + for (int i = 0; i < 11; i++) { int c = call[i]; @@ -48,6 +46,7 @@ int Packing::ihashcall(std::string call, int m) int j = p - chars; x = 38 * x + j; } + x = x * 47055833459LL; x = x >> (64 - m); @@ -66,17 +65,24 @@ std::string Packing::unpackcall(int x) const char *c3 = "0123456789"; const char *c4 = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - if (x == 0) + if (x == 0) { return "DE"; - if (x == 1) + } + + if (x == 1) { return "QRZ"; - if (x == 2) + } + + if (x == 2) { return "CQ"; + } + if (x <= 1002) { sprintf(tmp, "CQ %d", x - 3); - return tmp; + return std::string(tmp); } + if (x <= 532443) { x -= 1003; @@ -88,11 +94,10 @@ std::string Packing::unpackcall(int x) x %= 27; int ci4 = x; sprintf(tmp, "CQ %c%c%c%c", c4[ci1], c4[ci2], c4[ci3], c4[ci4]); - return tmp; + return std::string(tmp); } - if (x < NTOKENS) - { + if (x < NTOKENS) { return ""; } @@ -103,14 +108,13 @@ std::string Packing::unpackcall(int x) // 22-bit hash... std::string s; hashes_mu.lock(); - if (hashes22.count(x) > 0) - { + + if (hashes22.count(x) > 0) { s = hashes22[x]; - } - else - { + } else { s = "<...22>"; } + hashes_mu.unlock(); return s; } @@ -133,7 +137,7 @@ std::string Packing::unpackcall(int x) a[6] = '\0'; - return a; + return std::string(a); } // unpack a 15-bit grid square &c. @@ -172,44 +176,41 @@ std::string Packing::unpackgrid(int ng, int ir, int i3) ng -= NGBASE; - if (ng == 1) - { + if (ng == 1) { return " "; // ??? } - if (ng == 2) - { + if (ng == 2) { return "RRR "; } - if (ng == 3) - { + if (ng == 3) { return "RR73"; } - if (ng == 4) - { + if (ng == 4) { return "73 "; } int db = ng - 35; char tmp[16]; - if (db >= 0) - { + + if (db >= 0) { sprintf(tmp, "%s+%02d", ir ? "R" : "", db); - } - else - { + } else { sprintf(tmp, "%s-%02d", ir ? "R" : "", 0 - db); } - return tmp; + + return std::string(tmp); } void Packing::remember_call(std::string call) { hashes_mu.lock(); + if (call.size() >= 3 && call[0] != '<') { hashes22[ihashcall(call, 22)] = call; hashes12[ihashcall(call, 12)] = call; } + hashes_mu.unlock(); } @@ -236,11 +237,14 @@ std::string Packing::unpack_4(int a77[], std::string& call1str, std::string& cal } call[11] = '\0'; + std::string callstr(call); - remember_call(call); + remember_call(callstr); - if (un64(a77, 73, 1) == 1) { - return std::string("CQ ") + call; + if (un64(a77, 73, 1) == 1) + { + call1str = std::string("CQ ") + callstr; + return call1str; } int x12 = un64(a77, 0, 12); @@ -255,7 +259,6 @@ std::string Packing::unpack_4(int a77[], std::string& call1str, std::string& cal } hashes_mu.unlock(); - int swap = un64(a77, 70, 1); std::string msg; @@ -274,14 +277,16 @@ std::string Packing::unpack_4(int a77[], std::string& call1str, std::string& cal int suffix = un64(a77, 71, 2); - if (suffix == 1) { - msg += " RRR"; + if (suffix == 1) + { + locstr = " RRR"; } else if (suffix == 2) { - msg += " RR73"; + locstr = " RR73"; } else if (suffix == 3) { - msg += " 73"; + locstr = " 73"; } + msg += locstr; return msg; } @@ -323,7 +328,7 @@ std::string Packing::unpack_1(int a77[], std::string& call1str, std::string& cal remember_call(call1str); remember_call(call2str); - const char *pr = (i3 == 1 ? "/R" : "/P"); + const std::string pr = (i3 == 1 ? "/R" : "/P"); return call1str + (rover1 ? pr : "") + " " + call2str + (rover2 ? pr : "") + " " + locstr; } @@ -340,11 +345,13 @@ std::string Packing::unpack_0_0(int a77[], std::string& call1str, std::string& c const char *cc = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"; boost::multiprecision::int128_t x = un128(a77, 0, 71); std::string msg = "0123456789123"; + for (int i = 0; i < 13; i++) { msg[13 - 1 - i] = cc[(int) (x % 42)]; x = x / 42; } + call1str = msg; return msg; } @@ -392,6 +399,7 @@ std::string Packing::unpack_3(int a77[], std::string& call1str, std::string& cal int statei = serial - 8001; std::string serialstr; int nstates = sizeof(ru_states) / sizeof(ru_states[0]); + if (serial > 8000 && statei < nstates) { serialstr = ru_states[statei]; @@ -400,16 +408,17 @@ std::string Packing::unpack_3(int a77[], std::string& call1str, std::string& cal { char tmp[32]; sprintf(tmp, "%04d", serial); - serialstr = tmp; + serialstr = std::string(tmp); } std::string msg; - if (tu) - { + if (tu) { msg += "TU; "; } + msg += call1str + " " + call2str + " "; + if (r) { msg += "R "; @@ -417,8 +426,9 @@ std::string Packing::unpack_3(int a77[], std::string& call1str, std::string& cal { char tmp[16]; sprintf(tmp, "%d ", rst); - msg += tmp; + msg += std::string(tmp); } + msg += serialstr; remember_call(call1str); @@ -479,7 +489,7 @@ std::string Packing::unpack_0_3(int a77[], int n3, std::string& call1str, std::s { char tmp[16]; sprintf(tmp, "%d%c ", n_transmitters + 1, clss + 'A'); - msg += tmp; + msg += std::string(tmp); } if (section - 1 >= 0 && section - 1 < (int)(sizeof(sections) / sizeof(sections[0]))) { @@ -531,8 +541,9 @@ std::string Packing::unpack(int a77[], std::string& call1, std::string& call2, s } char tmp[64]; + call1 = "UNK"; sprintf(tmp, "UNK i3=%d n3=%d", i3, n3); - return tmp; + return std::string(tmp); } } // namespace FT8 diff --git a/ft8/unpack.h b/ft8/unpack.h index 4e50349ae..2fabb3ef2 100644 --- a/ft8/unpack.h +++ b/ft8/unpack.h @@ -24,7 +24,7 @@ #include #include -#include +#include #include "export.h" @@ -36,7 +36,7 @@ public: std::string unpack(int a91[], std::string& call1str, std::string& call2str, std::string& locstr); private: - int ihashcall(std::string call, int m); + static int ihashcall(std::string call, int m); std::string unpackcall(int x); std::string unpackgrid(int ng, int ir, int i3); void remember_call(std::string call); @@ -46,7 +46,7 @@ private: std::string unpack_3(int a77[], std::string& call1str, std::string& call2str, std::string& locstr); std::string unpack_0_3(int a77[], int n3, std::string& call1str, std::string& call2str, std::string& locstr); - QMutex hashes_mu; + QRecursiveMutex hashes_mu; std::map hashes12; std::map hashes22; diff --git a/plugins/channelrx/demodft8/CMakeLists.txt b/plugins/channelrx/demodft8/CMakeLists.txt index 05df0ff0a..1117c9925 100644 --- a/plugins/channelrx/demodft8/CMakeLists.txt +++ b/plugins/channelrx/demodft8/CMakeLists.txt @@ -24,6 +24,7 @@ set(demodft8_HEADERS include_directories( ${CMAKE_SOURCE_DIR}/swagger/sdrangel/code/qt5/client + ${CMAKE_SOURCE_DIR}/ft8 ) if(NOT SERVER_MODE) @@ -57,6 +58,7 @@ target_link_libraries(${TARGET_NAME} sdrbase ${TARGET_LIB_GUI} swagger + ft8 ) install(TARGETS ${TARGET_NAME} DESTINATION ${INSTALL_FOLDER}) diff --git a/plugins/channelrx/demodft8/ft8demod.cpp b/plugins/channelrx/demodft8/ft8demod.cpp index 2c380b94e..6672c6a20 100644 --- a/plugins/channelrx/demodft8/ft8demod.cpp +++ b/plugins/channelrx/demodft8/ft8demod.cpp @@ -276,6 +276,18 @@ void FT8Demod::applySettings(const FT8DemodSettings& settings, bool force) if ((m_settings.m_agc != settings.m_agc) || force) { reverseAPIKeys.append("agc"); } + if ((m_settings.m_recordWav != settings.m_recordWav) || force) { + reverseAPIKeys.append("recordWav"); + } + if ((m_settings.m_logMessages != settings.m_logMessages) || force) { + reverseAPIKeys.append("logMessages"); + } + if ((m_settings.m_nbDecoderThreads != settings.m_nbDecoderThreads) || force) { + reverseAPIKeys.append("nbDecoderThreads"); + } + if ((m_settings.m_decoderTimeBudget != settings.m_decoderTimeBudget) || force) { + reverseAPIKeys.append("decoderTimeBudget"); + } if (m_settings.m_streamIndex != settings.m_streamIndex) { @@ -444,6 +456,18 @@ void FT8Demod::webapiUpdateChannelSettings( if (channelSettingsKeys.contains("agc")) { settings.m_agc = response.getFt8DemodSettings()->getAgc() != 0; } + if (channelSettingsKeys.contains("recordWav")) { + settings.m_recordWav = response.getFt8DemodSettings()->getRecordWav() != 0; + } + if (channelSettingsKeys.contains("m_logMessages")) { + settings.m_logMessages = response.getFt8DemodSettings()->getLogMessages() != 0; + } + if (channelSettingsKeys.contains("nbDecoderThreads")) { + settings.m_nbDecoderThreads = response.getFt8DemodSettings()->getNbDecoderThreads(); + } + if (channelSettingsKeys.contains("decoderTimeBudget")) { + settings.m_decoderTimeBudget = response.getFt8DemodSettings()->getDecoderTimeBudget(); + } if (channelSettingsKeys.contains("rgbColor")) { settings.m_rgbColor = response.getFt8DemodSettings()->getRgbColor(); } @@ -500,6 +524,10 @@ void FT8Demod::webapiFormatChannelSettings(SWGSDRangel::SWGChannelSettings& resp response.getFt8DemodSettings()->setFftWindow((int) settings.m_filterBank[settings.m_filterIndex].m_fftWindow); response.getFt8DemodSettings()->setVolume(settings.m_volume); response.getFt8DemodSettings()->setAgc(settings.m_agc ? 1 : 0); + response.getFt8DemodSettings()->setRecordWav(settings.m_recordWav ? 1 : 0); + response.getFt8DemodSettings()->setLogMessages(settings.m_logMessages ? 1 : 0); + response.getFt8DemodSettings()->setNbDecoderThreads(settings.m_nbDecoderThreads); + response.getFt8DemodSettings()->setDecoderTimeBudget(settings.m_decoderTimeBudget); response.getFt8DemodSettings()->setRgbColor(settings.m_rgbColor); if (response.getFt8DemodSettings()->getTitle()) { @@ -671,6 +699,18 @@ void FT8Demod::webapiFormatChannelSettings( if (channelSettingsKeys.contains("agc") || force) { swgFT8DemodSettings->setAgc(settings.m_agc ? 1 : 0); } + if (channelSettingsKeys.contains("recordWav") || force) { + swgFT8DemodSettings->setRecordWav(settings.m_recordWav ? 1 : 0); + } + if (channelSettingsKeys.contains("logMessages") || force) { + swgFT8DemodSettings->setRecordWav(settings.m_logMessages ? 1 : 0); + } + if (channelSettingsKeys.contains("nbDecoderThreads") || force) { + swgFT8DemodSettings->setNbDecoderThreads(settings.m_nbDecoderThreads); + } + if (channelSettingsKeys.contains("decoderTimeBudget") || force) { + swgFT8DemodSettings->setDecoderTimeBudget(settings.m_decoderTimeBudget); + } if (channelSettingsKeys.contains("rgbColor") || force) { swgFT8DemodSettings->setRgbColor(settings.m_rgbColor); } diff --git a/plugins/channelrx/demodft8/ft8demodbaseband.cpp b/plugins/channelrx/demodft8/ft8demodbaseband.cpp index f9a671803..9b3156778 100644 --- a/plugins/channelrx/demodft8/ft8demodbaseband.cpp +++ b/plugins/channelrx/demodft8/ft8demodbaseband.cpp @@ -58,7 +58,8 @@ FT8DemodBaseband::FT8DemodBaseband() : this, &FT8DemodBaseband::bufferReady, m_ft8DemodWorker, - &FT8DemodWorker::processBuffer + &FT8DemodWorker::processBuffer, + Qt::QueuedConnection ); m_workerThread->start(); @@ -204,6 +205,30 @@ void FT8DemodBaseband::applySettings(const FT8DemodSettings& settings, bool forc } } + if ((m_settings.m_filterBank[m_settings.m_filterIndex].m_lowCutoff != settings.m_filterBank[settings.m_filterIndex].m_lowCutoff) || force) { + m_ft8DemodWorker->setLowFrequency(settings.m_filterBank[settings.m_filterIndex].m_lowCutoff); + } + + if ((m_settings.m_filterBank[m_settings.m_filterIndex].m_rfBandwidth != settings.m_filterBank[settings.m_filterIndex].m_rfBandwidth) || force) { + m_ft8DemodWorker->setHighFrequency(settings.m_filterBank[settings.m_filterIndex].m_rfBandwidth); + } + + if ((settings.m_recordWav != m_settings.m_recordWav) || force) { + m_ft8DemodWorker->setRecordSamples(settings.m_recordWav); + } + + if ((settings.m_logMessages != m_settings.m_logMessages) || force) { + m_ft8DemodWorker->setLogMessages(settings.m_logMessages); + } + + if ((settings.m_nbDecoderThreads != m_settings.m_nbDecoderThreads) || force) { + m_ft8DemodWorker->setNbDecoderThreads(settings.m_nbDecoderThreads); + } + + if ((settings.m_decoderTimeBudget != m_settings.m_decoderTimeBudget) || force) { + m_ft8DemodWorker->setDecoderTimeBudget(settings.m_decoderTimeBudget); + } + m_sink.applySettings(settings, force); m_settings = settings; } diff --git a/plugins/channelrx/demodft8/ft8demodgui.cpp b/plugins/channelrx/demodft8/ft8demodgui.cpp index 3de5dda80..e9ff7e396 100644 --- a/plugins/channelrx/demodft8/ft8demodgui.cpp +++ b/plugins/channelrx/demodft8/ft8demodgui.cpp @@ -204,6 +204,32 @@ void FT8DemodGUI::on_filterIndex_valueChanged(int value) applyBandwidths(m_settings.m_filterBank[m_settings.m_filterIndex].m_spanLog2, true); // does applySettings(true) } +void FT8DemodGUI::on_recordWav_toggled(bool checked) +{ + m_settings.m_recordWav = checked; + applySettings(); +} + +void FT8DemodGUI::on_logMessages_toggled(bool checked) +{ + m_settings.m_logMessages = checked; + applySettings(); +} + +void FT8DemodGUI::on_nbThreads_valueChanged(int value) +{ + ui->nbThreadsText->setText(tr("%1").arg(value)); + m_settings.m_nbDecoderThreads = value; + applySettings(); +} + +void FT8DemodGUI::on_timeBudget_valueChanged(int value) +{ + m_settings.m_decoderTimeBudget = value / 10.0f; + ui->timeBudgetText->setText(tr("%1").arg(m_settings.m_decoderTimeBudget, 0, 'f', 1)); + applySettings(); +} + void FT8DemodGUI::onMenuDialogCalled(const QPoint &p) { if (m_contextMenuType == ContextMenuChannelSettings) @@ -335,6 +361,9 @@ FT8DemodGUI::FT8DemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseban applyBandwidths(m_settings.m_filterBank[m_settings.m_filterIndex].m_spanLog2, true); // does applySettings(true) DialPopup::addPopupsToChildDials(this); + + // Resize the table using dummy data + resizeMessageTable(); } FT8DemodGUI::~FT8DemodGUI() @@ -500,6 +529,13 @@ void FT8DemodGUI::displaySettings() ui->volume->setValue(volume); ui->volumeText->setText(QString("%1").arg(volume)); + ui->recordWav->setChecked(m_settings.m_recordWav); + ui->logMessages->setChecked(m_settings.m_logMessages); + ui->nbThreads->setValue(m_settings.m_nbDecoderThreads); + ui->nbThreadsText->setText(tr("%1").arg(m_settings.m_nbDecoderThreads)); + ui->timeBudget->setValue(m_settings.m_decoderTimeBudget*10); + ui->timeBudgetText->setText(tr("%1").arg(m_settings.m_decoderTimeBudget, 0, 'f', 1)); + updateIndexLabel(); getRollupContents()->restoreState(m_rollupState); @@ -549,9 +585,33 @@ void FT8DemodGUI::makeUIConnections() QObject::connect(ui->spanLog2, &QSlider::valueChanged, this, &FT8DemodGUI::on_spanLog2_valueChanged); QObject::connect(ui->fftWindow, QOverload::of(&QComboBox::currentIndexChanged), this, &FT8DemodGUI::on_fftWindow_currentIndexChanged); QObject::connect(ui->filterIndex, &QDial::valueChanged, this, &FT8DemodGUI::on_filterIndex_valueChanged); + QObject::connect(ui->recordWav, &ButtonSwitch::toggled, this, &FT8DemodGUI::on_recordWav_toggled); + QObject::connect(ui->logMessages, &ButtonSwitch::toggled, this, &FT8DemodGUI::on_logMessages_toggled); + QObject::connect(ui->nbThreads, &QDial::valueChanged, this, &FT8DemodGUI::on_nbThreads_valueChanged); + QObject::connect(ui->timeBudget, &QDial::valueChanged, this, &FT8DemodGUI::on_timeBudget_valueChanged); } void FT8DemodGUI::updateAbsoluteCenterFrequency() { setStatusFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); } + +void FT8DemodGUI::resizeMessageTable() +{ + // Fill table with a row of dummy data that will size the columns nicely + // Trailing spaces are for sort arrow + int row = ui->messages->rowCount(); + ui->messages->setRowCount(row + 1); + ui->messages->setItem(row, MESSAGE_COL_UTC, new QTableWidgetItem("000000")); + ui->messages->setItem(row, MESSAGE_COL_N, new QTableWidgetItem("0")); + ui->messages->setItem(row, MESSAGE_COL_SNR, new QTableWidgetItem("-24")); + ui->messages->setItem(row, MESSAGE_COL_DEC, new QTableWidgetItem("174")); + ui->messages->setItem(row, MESSAGE_COL_DT, new QTableWidgetItem("0.0")); + ui->messages->setItem(row, MESSAGE_COL_DF, new QTableWidgetItem("0000")); + ui->messages->setItem(row, MESSAGE_COL_CALL1, new QTableWidgetItem("123456789ABCD")); + ui->messages->setItem(row, MESSAGE_COL_CALL2, new QTableWidgetItem("HF7SIEMA")); + ui->messages->setItem(row, MESSAGE_COL_LOC, new QTableWidgetItem("JN00")); + ui->messages->setItem(row, MESSAGE_COL_INFO, new QTableWidgetItem("hint1")); + ui->messages->resizeColumnsToContents(); + ui->messages->removeRow(row); +} diff --git a/plugins/channelrx/demodft8/ft8demodgui.h b/plugins/channelrx/demodft8/ft8demodgui.h index 462564275..22d3bfe89 100644 --- a/plugins/channelrx/demodft8/ft8demodgui.h +++ b/plugins/channelrx/demodft8/ft8demodgui.h @@ -100,6 +100,21 @@ private: void leaveEvent(QEvent*); void enterEvent(EnterEventType*); + void resizeMessageTable(); + + enum MessageCol { + MESSAGE_COL_UTC, + MESSAGE_COL_N, + MESSAGE_COL_SNR, + MESSAGE_COL_DEC, + MESSAGE_COL_DT, + MESSAGE_COL_DF, + MESSAGE_COL_CALL1, + MESSAGE_COL_CALL2, + MESSAGE_COL_LOC, + MESSAGE_COL_INFO, + }; + private slots: void on_deltaFrequency_changed(qint64 value); void on_BW_valueChanged(int value); @@ -109,6 +124,10 @@ private slots: void on_spanLog2_valueChanged(int value); void on_fftWindow_currentIndexChanged(int index); void on_filterIndex_valueChanged(int value); + void on_recordWav_toggled(bool checked); + void on_logMessages_toggled(bool checked); + void on_nbThreads_valueChanged(int value); + void on_timeBudget_valueChanged(int value); void onWidgetRolled(QWidget* widget, bool rollDown); void onMenuDialogCalled(const QPoint& p); void handleInputMessages(); diff --git a/plugins/channelrx/demodft8/ft8demodgui.ui b/plugins/channelrx/demodft8/ft8demodgui.ui index ad055f60c..04be3935e 100644 --- a/plugins/channelrx/demodft8/ft8demodgui.ui +++ b/plugins/channelrx/demodft8/ft8demodgui.ui @@ -7,7 +7,7 @@ 0 0 414 - 190 + 731 @@ -667,9 +667,9 @@ 10 - 170 + 193 218 - 284 + 261 @@ -737,6 +737,298 @@ + + + + 0 + 460 + 412 + 251 + + + + + 0 + 0 + + + + + 412 + 0 + + + + FT8 details + + + + 2 + + + 2 + + + 3 + + + 2 + + + 3 + + + + + + + Th + + + + + + + + 24 + 24 + + + + Number of decoder threads + + + 2 + + + 12 + + + 1 + + + 1 + + + 6 + + + + + + + 6 + + + + + + + Qt::Vertical + + + + + + + TB + + + + + + + + 24 + 24 + + + + Decoder time budget (seconds) + + + 5 + + + 50 + + + 1 + + + 1 + + + 25 + + + + + + + 2.5 + + + + + + + Qt::Vertical + + + + + + + Dec + + + + + + + Number of messages decoded in the last sequence + + + 00 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Log messages + + + ... + + + + :/listing.png:/listing.png + + + + + + + Record wav files + + + + + + + :/record_off.png:/record_off.png + + + + + + + + + Decoded messages + + + QAbstractItemView::NoEditTriggers + + + + UTC + + + Sequence UTC time HHMMSS + + + + + P + + + Successful decoder pass index + + + + + SNR + + + Signal to noise ratio (dB) in 2.5 kHz bandwidth + + + + + OKb + + + Number of correct bits before correction + + + + + dt + + + Time delay + + + + + df + + + Frequency shift + + + + + Call1 + + + Fist call area + + + + + Call2 + + + Second call area + + + + + Loc + + + Locator area + + + + + Info + + + Extra decoder information + + + + + + diff --git a/plugins/channelrx/demodft8/ft8demodsettings.cpp b/plugins/channelrx/demodft8/ft8demodsettings.cpp index 5a46ebb3a..c5f8dc359 100644 --- a/plugins/channelrx/demodft8/ft8demodsettings.cpp +++ b/plugins/channelrx/demodft8/ft8demodsettings.cpp @@ -43,6 +43,10 @@ FT8DemodSettings::FT8DemodSettings() : void FT8DemodSettings::resetToDefaults() { m_agc = false; + m_recordWav = false; + m_logMessages = false; + m_nbDecoderThreads = 6; + m_decoderTimeBudget = 0.5; m_volume = 1.0; m_inputFrequencyOffset = 0; m_rgbColor = QColor(0, 192, 255).rgb(); @@ -69,6 +73,10 @@ QByteArray FT8DemodSettings::serialize() const } s.writeU32(5, m_rgbColor); + s.writeBool(6, m_recordWav); + s.writeBool(7, m_logMessages); + s.writeS32(8, m_nbDecoderThreads); + s.writeFloat(9, m_decoderTimeBudget); s.writeBool(11, m_agc); s.writeString(16, m_title); s.writeBool(18, m_useReverseAPI); @@ -126,6 +134,10 @@ bool FT8DemodSettings::deserialize(const QByteArray& data) } d.readU32(5, &m_rgbColor); + d.readBool(6, &m_recordWav, false); + d.readBool(7, &m_logMessages, false); + d.readS32(8, &m_nbDecoderThreads, 6); + d.readFloat(9, &m_decoderTimeBudget, 0.5); d.readBool(11, &m_agc, false); d.readString(16, &m_title, "SSB Demodulator"); d.readBool(18, &m_useReverseAPI, false); diff --git a/plugins/channelrx/demodft8/ft8demodsettings.h b/plugins/channelrx/demodft8/ft8demodsettings.h index 451f87d97..481de9335 100644 --- a/plugins/channelrx/demodft8/ft8demodsettings.h +++ b/plugins/channelrx/demodft8/ft8demodsettings.h @@ -46,8 +46,11 @@ struct FT8DemodSettings // Real m_rfBandwidth; // Real m_lowCutoff; Real m_volume; - // int m_spanLog2; bool m_agc; + bool m_recordWav; + bool m_logMessages; + int m_nbDecoderThreads; + float m_decoderTimeBudget; quint32 m_rgbColor; QString m_title; int m_streamIndex; //!< MIMO channel. Not relevant when connected to SI (single Rx). diff --git a/plugins/channelrx/demodft8/ft8demodworker.cpp b/plugins/channelrx/demodft8/ft8demodworker.cpp index 7f6595810..6df37fb8f 100644 --- a/plugins/channelrx/demodft8/ft8demodworker.cpp +++ b/plugins/channelrx/demodft8/ft8demodworker.cpp @@ -20,11 +20,84 @@ #include #include "dsp/wavfilerecord.h" +#include "util/messagequeue.h" +#include "util/ft8message.h" #include "ft8demodsettings.h" #include "ft8demodworker.h" -FT8DemodWorker::FT8DemodWorker() +FT8DemodWorker::FT8Callback::FT8Callback(const QDateTime& periodTS, FT8::Packing& packing) : + m_packing(packing), + m_periodTS(periodTS) +{ + m_msgReportFT8Messages = MsgReportFT8Messages::create(); +} + +int FT8DemodWorker::FT8Callback::hcb( + int *a91, + float hz0, + float off, + const char *comment, + float snr, + int pass, + int correct_bits +) +{ + std::string call1; + std::string call2; + std::string loc; + std::string msg = m_packing.unpack(a91, call1, call2, loc); + + cycle_mu.lock(); + + if (cycle_already.count(msg) > 0) + { + // already decoded this message on this cycle + cycle_mu.unlock(); + return 1; // 1 => already seen, don't subtract. + } + + cycle_already[msg] = true; + cycle_mu.unlock(); + + QList& ft8Messages = m_msgReportFT8Messages->getFT8Messages(); + ft8Messages.push_back(FT8Message()); + FT8Message& ft8Message = ft8Messages.back(); + + ft8Message.ts = m_periodTS; + ft8Message.pass = pass; + ft8Message.snr = (int) snr; + ft8Message.nbCorrectBits = correct_bits; + ft8Message.dt = off - 0.5; + ft8Message.df = hz0; + ft8Message.call1 = QString(call1.c_str()); + ft8Message.call2 = QString(call2.c_str()); + ft8Message.loc = QString(loc.c_str()); + ft8Message.decoderInfo = QString(comment); + + qDebug("FT8DemodWorker::FT8Callback::hcb: %d %3d %3d %5.2f %6.1f %s [%s:%s:%s] (%s)", + pass, + (int)snr, + correct_bits, + off - 0.5, + hz0, + msg.c_str(), + call1.c_str(), + call2.c_str(), + loc.c_str(), + comment + ); + + return 2; // 2 => new decode, do subtract. +} + +FT8DemodWorker::FT8DemodWorker() : + m_recordSamples(false), + m_nbDecoderThreads(6), + m_decoderTimeBudget(0.5), + m_lowFreq(200), + m_highFreq(3000), + m_reportingMessageQueue(nullptr) { QString relPath = "sdrangel/ft8/save"; QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); @@ -38,16 +111,58 @@ FT8DemodWorker::~FT8DemodWorker() void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) { - qDebug("FT8DemodWorker::processBuffer: %s", qPrintable(periodTS.toString("yyyy-MM-dd HH:mm:ss"))); - WavFileRecord *wavFileRecord = new WavFileRecord(FT8DemodSettings::m_ft8SampleRate); - QFileInfo wfi(QDir(m_samplesPath), periodTS.toString("yyyyMMdd_HHmmss")); - QString wpath = wfi.absoluteFilePath(); - qDebug("FT8DemodWorker::processBuffer: WAV file: %s.wav", qPrintable(wpath)); - wavFileRecord->setFileName(wpath); - wavFileRecord->setFileBaseIsFileName(true); - wavFileRecord->setMono(true); - wavFileRecord->startRecording(); - wavFileRecord->writeMono(buffer, 15*FT8DemodSettings::m_ft8SampleRate); - wavFileRecord->stopRecording(); - delete wavFileRecord; + qDebug("FT8DemodWorker::processBuffer: %s %d:%f [%d:%d]", qPrintable(periodTS.toString("yyyy-MM-dd HH:mm:ss")), + m_nbDecoderThreads, m_decoderTimeBudget, m_lowFreq, m_highFreq); + + if (m_recordSamples) + { + WavFileRecord *wavFileRecord = new WavFileRecord(FT8DemodSettings::m_ft8SampleRate); + QFileInfo wfi(QDir(m_samplesPath), periodTS.toString("yyyyMMdd_HHmmss")); + QString wpath = wfi.absoluteFilePath(); + qDebug("FT8DemodWorker::processBuffer: WAV file: %s.wav", qPrintable(wpath)); + wavFileRecord->setFileName(wpath); + wavFileRecord->setFileBaseIsFileName(true); + wavFileRecord->setMono(true); + wavFileRecord->startRecording(); + wavFileRecord->writeMono(buffer, 15*FT8DemodSettings::m_ft8SampleRate); + wavFileRecord->stopRecording(); + delete wavFileRecord; + } + + int hints[2] = { 2, 0 }; // CQ + FT8Callback ft8Callback(periodTS, m_packing); + m_ft8Decoder.getParams().nthreads = m_nbDecoderThreads; + std::vector samples(15*FT8DemodSettings::m_ft8SampleRate); + + std::transform( + buffer, + buffer + (15*FT8DemodSettings::m_ft8SampleRate), + samples.begin(), + [](const int16_t& s) -> float { return s / 32768.0f; } + ); + + m_ft8Decoder.entry( + samples.data(), + samples.size(), + 0.5 * FT8DemodSettings::m_ft8SampleRate, + FT8DemodSettings::m_ft8SampleRate, + m_lowFreq, + m_highFreq, + hints, + hints, + m_decoderTimeBudget, + m_decoderTimeBudget, + &ft8Callback, + 0, + (struct FT8::cdecode *) nullptr + ); + + m_ft8Decoder.wait(m_decoderTimeBudget + 1.0); // add one second to budget to force quit threads + qDebug("FT8DemodWorker::processBuffer: done: %d messages", ft8Callback.getReportMessage()->getFT8Messages().size()); + + if (m_reportingMessageQueue) { + m_reportingMessageQueue->push(ft8Callback.getReportMessage()); + } else { + delete ft8Callback.getReportMessage(); + } } diff --git a/plugins/channelrx/demodft8/ft8demodworker.h b/plugins/channelrx/demodft8/ft8demodworker.h index a097c774b..811f5ad27 100644 --- a/plugins/channelrx/demodft8/ft8demodworker.h +++ b/plugins/channelrx/demodft8/ft8demodworker.h @@ -20,7 +20,12 @@ #include +#include "ft8.h" +#include "unpack.h" + class QDateTime; +class MessageQueue; +class MsgReportFT8Messages; class FT8DemodWorker : public QObject { @@ -30,9 +35,52 @@ public: ~FT8DemodWorker(); void processBuffer(int16_t *buffer, QDateTime periodTS); + void setRecordSamples(bool recordSamples) { m_recordSamples = recordSamples; } + void setLogMessages(bool logMessages) { m_logMessages = logMessages; } + void setNbDecoderThreads(int nbDecoderThreads) { m_nbDecoderThreads = nbDecoderThreads; } + void setDecoderTimeBudget(float decoderTimeBudget) { m_decoderTimeBudget = decoderTimeBudget; } + void setLowFrequency(int lowFreq) { m_lowFreq = lowFreq; } + void setHighFrequency(int highFreq) { m_highFreq = highFreq; } + void setReportingMessageQueue(MessageQueue *messageQueue) { m_reportingMessageQueue = messageQueue; } private: + class FT8Callback : public FT8::CallbackInterface + { + public: + FT8Callback(const QDateTime& periodTS, FT8::Packing& packing); + virtual int hcb( + int *a91, + float hz0, + float off, + const char *comment, + float snr, + int pass, + int correct_bits + ); + const std::map& getMsgMap() { + return cycle_already; + } + MsgReportFT8Messages *getReportMessage() { + return m_msgReportFT8Messages; + } + private: + QMutex cycle_mu; + std::map cycle_already; + FT8::Packing& m_packing; + MsgReportFT8Messages *m_msgReportFT8Messages; + const QDateTime& m_periodTS; + }; + QString m_samplesPath; + bool m_recordSamples; + bool m_logMessages; + int m_nbDecoderThreads; + float m_decoderTimeBudget; + int m_lowFreq; + int m_highFreq; + FT8::FT8Decoder m_ft8Decoder; + FT8::Packing m_packing; + MessageQueue *m_reportingMessageQueue; }; #endif // INCLUDE_FT8DEMODWORKER_H diff --git a/sdrbase/CMakeLists.txt b/sdrbase/CMakeLists.txt index 13faff1c9..146a63129 100644 --- a/sdrbase/CMakeLists.txt +++ b/sdrbase/CMakeLists.txt @@ -185,6 +185,7 @@ set(sdrbase_SOURCES util/fixedtraits.cpp util/fits.cpp util/flightinformation.cpp + util/ft8message.cpp util/giro.cpp util/golay2312.cpp util/httpdownloadmanager.cpp @@ -408,6 +409,7 @@ set(sdrbase_HEADERS util/fixedtraits.h util/fits.h util/flightinformation.h + util/ft8message.h util/giro.h util/golay2312.h util/httpdownloadmanager.h diff --git a/sdrbase/resources/webapi/doc/html2/index.html b/sdrbase/resources/webapi/doc/html2/index.html index bae0ed842..6fdc88ef0 100644 --- a/sdrbase/resources/webapi/doc/html2/index.html +++ b/sdrbase/resources/webapi/doc/html2/index.html @@ -5611,6 +5611,22 @@ margin-bottom: 20px; "type" : "integer", "description" : "AGC (1 if AGC active else 0)" }, + "recordWav" : { + "type" : "integer", + "description" : "Record received audio as 12000S/s 16 bit .wav file\n * 0 - Do not record\n * 1 - Record as sdrangel/ft8/save/YYYYMMDD_HHMMSS.wav in writable location\n" + }, + "logMessages" : { + "type" : "integer", + "description" : "Log decoded messages in WSJT CALL.TXT format\n * 0 - Do not log messages\n * 1 - Log messages as sdrangel/ft8/logs/YYYYMMDD_call.txt in writable location (daily files)\n" + }, + "nbDecoderThreads" : { + "type" : "integer", + "description" : "Number of threads in the FT8 decoder" + }, + "decoderTimeBudget" : { + "type" : "number", + "format" : "float" + }, "rgbColor" : { "type" : "integer" }, @@ -56873,7 +56889,7 @@ except ApiException as e:
- Generated 2023-01-17T00:44:14.657+01:00 + Generated 2023-01-19T23:18:51.935+01:00
diff --git a/sdrbase/resources/webapi/doc/swagger/include/FT8Demod.yaml b/sdrbase/resources/webapi/doc/swagger/include/FT8Demod.yaml index c0cfd867e..145cc4c9e 100644 --- a/sdrbase/resources/webapi/doc/swagger/include/FT8Demod.yaml +++ b/sdrbase/resources/webapi/doc/swagger/include/FT8Demod.yaml @@ -33,6 +33,25 @@ FT8DemodSettings: agc: description: AGC (1 if AGC active else 0) type: integer + recordWav: + type: integer + description: > + Record received audio as 12000S/s 16 bit .wav file + * 0 - Do not record + * 1 - Record as sdrangel/ft8/save/YYYYMMDD_HHMMSS.wav in writable location + logMessages: + type: integer + description: > + Log decoded messages in WSJT CALL.TXT format + * 0 - Do not log messages + * 1 - Log messages as sdrangel/ft8/logs/YYYYMMDD_call.txt in writable location (daily files) + nbDecoderThreads: + type: integer + description: Number of threads in the FT8 decoder + decoderTimeBudget: + type: number + format: float + desctiption: Decoder time budget in seconds (will stop after running this time) rgbColor: type: integer title: diff --git a/sdrbase/util/ft8message.cpp b/sdrbase/util/ft8message.cpp new file mode 100644 index 000000000..75e1e7fdf --- /dev/null +++ b/sdrbase/util/ft8message.cpp @@ -0,0 +1,20 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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 "ft8message.h" + +MESSAGE_CLASS_DEFINITION(MsgReportFT8Messages, Message) diff --git a/sdrbase/util/ft8message.h b/sdrbase/util/ft8message.h new file mode 100644 index 000000000..151147056 --- /dev/null +++ b/sdrbase/util/ft8message.h @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2023 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_FT8MESSAGE_H +#define INCLUDE_FT8MESSAGE_H + +#include +#include +#include + +#include "export.h" +#include "message.h" + +struct SDRBASE_API FT8Message +{ + QDateTime ts; + int pass; + int snr; + int nbCorrectBits; + float dt; + float df; + QString call1; + QString call2; + QString loc; + QString decoderInfo; +}; + +class FT8_API MsgReportFT8Messages : public Message { + MESSAGE_CLASS_DECLARATION +public: + QList& getFT8Messages() { return m_ft8Messages; } + + static MsgReportFT8Messages* create() { + return new MsgReportFT8Messages(); + } + +private: + QList m_ft8Messages; + + MsgReportFT8Messages() : + Message() + { } +}; + +#endif // INCLUDE_FT8MESSAGE_H diff --git a/swagger/sdrangel/api/swagger/include/FT8Demod.yaml b/swagger/sdrangel/api/swagger/include/FT8Demod.yaml index f2a8013f0..646744d75 100644 --- a/swagger/sdrangel/api/swagger/include/FT8Demod.yaml +++ b/swagger/sdrangel/api/swagger/include/FT8Demod.yaml @@ -33,6 +33,25 @@ FT8DemodSettings: agc: description: AGC (1 if AGC active else 0) type: integer + recordWav: + type: integer + description: > + Record received audio as 12000S/s 16 bit .wav file + * 0 - Do not record + * 1 - Record as sdrangel/ft8/save/YYYYMMDD_HHMMSS.wav in writable location + logMessages: + type: integer + description: > + Log decoded messages in WSJT CALL.TXT format + * 0 - Do not log messages + * 1 - Log messages as sdrangel/ft8/logs/YYYYMMDD_call.txt in writable location (daily files) + nbDecoderThreads: + type: integer + description: Number of threads in the FT8 decoder + decoderTimeBudget: + type: number + format: float + desctiption: Decoder time budget in seconds (will stop after running this time) rgbColor: type: integer title: diff --git a/swagger/sdrangel/code/html2/index.html b/swagger/sdrangel/code/html2/index.html index bae0ed842..6fdc88ef0 100644 --- a/swagger/sdrangel/code/html2/index.html +++ b/swagger/sdrangel/code/html2/index.html @@ -5611,6 +5611,22 @@ margin-bottom: 20px; "type" : "integer", "description" : "AGC (1 if AGC active else 0)" }, + "recordWav" : { + "type" : "integer", + "description" : "Record received audio as 12000S/s 16 bit .wav file\n * 0 - Do not record\n * 1 - Record as sdrangel/ft8/save/YYYYMMDD_HHMMSS.wav in writable location\n" + }, + "logMessages" : { + "type" : "integer", + "description" : "Log decoded messages in WSJT CALL.TXT format\n * 0 - Do not log messages\n * 1 - Log messages as sdrangel/ft8/logs/YYYYMMDD_call.txt in writable location (daily files)\n" + }, + "nbDecoderThreads" : { + "type" : "integer", + "description" : "Number of threads in the FT8 decoder" + }, + "decoderTimeBudget" : { + "type" : "number", + "format" : "float" + }, "rgbColor" : { "type" : "integer" }, @@ -56873,7 +56889,7 @@ except ApiException as e:
- Generated 2023-01-17T00:44:14.657+01:00 + Generated 2023-01-19T23:18:51.935+01:00
diff --git a/swagger/sdrangel/code/qt5/client/SWGFT8DemodSettings.cpp b/swagger/sdrangel/code/qt5/client/SWGFT8DemodSettings.cpp index 58ef2436d..8fcd24b73 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFT8DemodSettings.cpp +++ b/swagger/sdrangel/code/qt5/client/SWGFT8DemodSettings.cpp @@ -44,6 +44,14 @@ SWGFT8DemodSettings::SWGFT8DemodSettings() { m_volume_isSet = false; agc = 0; m_agc_isSet = false; + record_wav = 0; + m_record_wav_isSet = false; + log_messages = 0; + m_log_messages_isSet = false; + nb_decoder_threads = 0; + m_nb_decoder_threads_isSet = false; + decoder_time_budget = 0.0f; + m_decoder_time_budget_isSet = false; rgb_color = 0; m_rgb_color_isSet = false; title = nullptr; @@ -90,6 +98,14 @@ SWGFT8DemodSettings::init() { m_volume_isSet = false; agc = 0; m_agc_isSet = false; + record_wav = 0; + m_record_wav_isSet = false; + log_messages = 0; + m_log_messages_isSet = false; + nb_decoder_threads = 0; + m_nb_decoder_threads_isSet = false; + decoder_time_budget = 0.0f; + m_decoder_time_budget_isSet = false; rgb_color = 0; m_rgb_color_isSet = false; title = new QString(""); @@ -125,6 +141,10 @@ SWGFT8DemodSettings::cleanup() { + + + + if(title != nullptr) { delete title; } @@ -174,6 +194,14 @@ SWGFT8DemodSettings::fromJsonObject(QJsonObject &pJson) { ::SWGSDRangel::setValue(&agc, pJson["agc"], "qint32", ""); + ::SWGSDRangel::setValue(&record_wav, pJson["recordWav"], "qint32", ""); + + ::SWGSDRangel::setValue(&log_messages, pJson["logMessages"], "qint32", ""); + + ::SWGSDRangel::setValue(&nb_decoder_threads, pJson["nbDecoderThreads"], "qint32", ""); + + ::SWGSDRangel::setValue(&decoder_time_budget, pJson["decoderTimeBudget"], "float", ""); + ::SWGSDRangel::setValue(&rgb_color, pJson["rgbColor"], "qint32", ""); ::SWGSDRangel::setValue(&title, pJson["title"], "QString", "QString"); @@ -236,6 +264,18 @@ SWGFT8DemodSettings::asJsonObject() { if(m_agc_isSet){ obj->insert("agc", QJsonValue(agc)); } + if(m_record_wav_isSet){ + obj->insert("recordWav", QJsonValue(record_wav)); + } + if(m_log_messages_isSet){ + obj->insert("logMessages", QJsonValue(log_messages)); + } + if(m_nb_decoder_threads_isSet){ + obj->insert("nbDecoderThreads", QJsonValue(nb_decoder_threads)); + } + if(m_decoder_time_budget_isSet){ + obj->insert("decoderTimeBudget", QJsonValue(decoder_time_budget)); + } if(m_rgb_color_isSet){ obj->insert("rgbColor", QJsonValue(rgb_color)); } @@ -353,6 +393,46 @@ SWGFT8DemodSettings::setAgc(qint32 agc) { this->m_agc_isSet = true; } +qint32 +SWGFT8DemodSettings::getRecordWav() { + return record_wav; +} +void +SWGFT8DemodSettings::setRecordWav(qint32 record_wav) { + this->record_wav = record_wav; + this->m_record_wav_isSet = true; +} + +qint32 +SWGFT8DemodSettings::getLogMessages() { + return log_messages; +} +void +SWGFT8DemodSettings::setLogMessages(qint32 log_messages) { + this->log_messages = log_messages; + this->m_log_messages_isSet = true; +} + +qint32 +SWGFT8DemodSettings::getNbDecoderThreads() { + return nb_decoder_threads; +} +void +SWGFT8DemodSettings::setNbDecoderThreads(qint32 nb_decoder_threads) { + this->nb_decoder_threads = nb_decoder_threads; + this->m_nb_decoder_threads_isSet = true; +} + +float +SWGFT8DemodSettings::getDecoderTimeBudget() { + return decoder_time_budget; +} +void +SWGFT8DemodSettings::setDecoderTimeBudget(float decoder_time_budget) { + this->decoder_time_budget = decoder_time_budget; + this->m_decoder_time_budget_isSet = true; +} + qint32 SWGFT8DemodSettings::getRgbColor() { return rgb_color; @@ -492,6 +572,18 @@ SWGFT8DemodSettings::isSet(){ if(m_agc_isSet){ isObjectUpdated = true; break; } + if(m_record_wav_isSet){ + isObjectUpdated = true; break; + } + if(m_log_messages_isSet){ + isObjectUpdated = true; break; + } + if(m_nb_decoder_threads_isSet){ + isObjectUpdated = true; break; + } + if(m_decoder_time_budget_isSet){ + isObjectUpdated = true; break; + } if(m_rgb_color_isSet){ isObjectUpdated = true; break; } diff --git a/swagger/sdrangel/code/qt5/client/SWGFT8DemodSettings.h b/swagger/sdrangel/code/qt5/client/SWGFT8DemodSettings.h index 4532fcb9a..4da757902 100644 --- a/swagger/sdrangel/code/qt5/client/SWGFT8DemodSettings.h +++ b/swagger/sdrangel/code/qt5/client/SWGFT8DemodSettings.h @@ -69,6 +69,18 @@ public: qint32 getAgc(); void setAgc(qint32 agc); + qint32 getRecordWav(); + void setRecordWav(qint32 record_wav); + + qint32 getLogMessages(); + void setLogMessages(qint32 log_messages); + + qint32 getNbDecoderThreads(); + void setNbDecoderThreads(qint32 nb_decoder_threads); + + float getDecoderTimeBudget(); + void setDecoderTimeBudget(float decoder_time_budget); + qint32 getRgbColor(); void setRgbColor(qint32 rgb_color); @@ -130,6 +142,18 @@ private: qint32 agc; bool m_agc_isSet; + qint32 record_wav; + bool m_record_wav_isSet; + + qint32 log_messages; + bool m_log_messages_isSet; + + qint32 nb_decoder_threads; + bool m_nb_decoder_threads_isSet; + + float decoder_time_budget; + bool m_decoder_time_budget_isSet; + qint32 rgb_color; bool m_rgb_color_isSet;