From 9bb9493afdba18fd2fbc4e6ea902d2a85ca231f7 Mon Sep 17 00:00:00 2001 From: f4exb Date: Sun, 1 Mar 2026 22:21:16 +0100 Subject: [PATCH] FT8 demod: FT4 support (1) --- plugins/channelrx/demodft8/ft8buffer.cpp | 7 +- plugins/channelrx/demodft8/ft8buffer.h | 2 +- .../channelrx/demodft8/ft8demodbaseband.cpp | 33 +++-- plugins/channelrx/demodft8/ft8demodbaseband.h | 2 +- .../channelrx/demodft8/ft8demodsettings.cpp | 113 +++++++++++++++--- plugins/channelrx/demodft8/ft8demodsettings.h | 12 ++ .../demodft8/ft8demodsettingsdialog.cpp | 28 +++++ .../demodft8/ft8demodsettingsdialog.h | 1 + .../demodft8/ft8demodsettingsdialog.ui | 41 +++++++ plugins/channelrx/demodft8/ft8demodworker.cpp | 52 +++++++- plugins/channelrx/demodft8/ft8demodworker.h | 3 + .../channelrx/demodft8/pskreporterworker.cpp | 7 +- .../channelrx/demodft8/pskreporterworker.h | 3 +- 13 files changed, 264 insertions(+), 40 deletions(-) diff --git a/plugins/channelrx/demodft8/ft8buffer.cpp b/plugins/channelrx/demodft8/ft8buffer.cpp index d8daa1366..c63703030 100644 --- a/plugins/channelrx/demodft8/ft8buffer.cpp +++ b/plugins/channelrx/demodft8/ft8buffer.cpp @@ -18,6 +18,7 @@ /////////////////////////////////////////////////////////////////////////////////// #include +#include #include "ft8demodsettings.h" #include "ft8buffer.h" @@ -46,8 +47,10 @@ void FT8Buffer::feed(int16_t sample) } } -void FT8Buffer::getCurrentBuffer(int16_t *bufferCopy) +void FT8Buffer::getCurrentBuffer(int16_t *bufferCopy, int samplesToCopy) { QMutexLocker mlock(&m_mutex); - std::copy(&m_buffer[m_sampleIndex], &m_buffer[m_sampleIndex + m_bufferSize], bufferCopy); + const int samples = std::max(1, std::min(samplesToCopy, m_bufferSize)); + const int start = m_sampleIndex + m_bufferSize - samples; + std::copy(&m_buffer[start], &m_buffer[start + samples], bufferCopy); } diff --git a/plugins/channelrx/demodft8/ft8buffer.h b/plugins/channelrx/demodft8/ft8buffer.h index 5733a26a5..3bf6167c2 100644 --- a/plugins/channelrx/demodft8/ft8buffer.h +++ b/plugins/channelrx/demodft8/ft8buffer.h @@ -31,7 +31,7 @@ public: ~FT8Buffer(); void feed(int16_t sample); - void getCurrentBuffer(int16_t *bufferCopy); + void getCurrentBuffer(int16_t *bufferCopy, int samplesToCopy); private: int16_t *m_buffer; diff --git a/plugins/channelrx/demodft8/ft8demodbaseband.cpp b/plugins/channelrx/demodft8/ft8demodbaseband.cpp index 5edf60ec3..eb7d3eecf 100644 --- a/plugins/channelrx/demodft8/ft8demodbaseband.cpp +++ b/plugins/channelrx/demodft8/ft8demodbaseband.cpp @@ -18,6 +18,7 @@ #include #include +#include #include "dsp/dspcommands.h" #include "dsp/spectrumvis.h" @@ -33,6 +34,7 @@ FT8DemodBaseband::FT8DemodBaseband() : m_channelizer(&m_sink), m_messageQueueToGUI(nullptr), m_spectrumVis(nullptr), + m_lastProcessPeriodIndex(-1), m_deviceCenterFrequency(0) { qDebug("FT8DemodBaseband::FT8DemodBaseband"); @@ -103,6 +105,7 @@ void FT8DemodBaseband::reset() QMutexLocker mutexLocker(&m_mutex); m_sampleFifo.reset(); m_channelSampleRate = 0; + m_lastProcessPeriodIndex = -1; } void FT8DemodBaseband::setMessageQueueToGUI(MessageQueue *messageQueue) @@ -289,6 +292,14 @@ void FT8DemodBaseband::applySettings(const QStringList& settingsKeys, const FT8D m_ft8DemodWorker->setVerifyOSD(settings.m_verifyOSD); } + if ((settingsKeys.contains("decoderMode") && (settings.m_decoderMode != m_settings.m_decoderMode)) || force) + { + m_ft8DemodWorker->setDecoderMode(settings.m_decoderMode); + m_pskReporterWorker->setTxMode(FT8DemodSettings::getDecoderModeString(settings.m_decoderMode)); + m_ft8DemodWorker->invalidateSequence(); + m_lastProcessPeriodIndex = -1; + } + m_sink.applySettings(settingsKeys, settings, force); if (force) { @@ -313,20 +324,22 @@ void FT8DemodBaseband::setBasebandSampleRate(int sampleRate) void FT8DemodBaseband::tick() { QDateTime nowUTC = QDateTime::currentDateTimeUtc(); + const int periodMs = FT8DemodSettings::getDecoderFrameDurationMs(m_settings.m_decoderMode); + const int activeWindowMs = std::max(periodMs - 1000, 1); + const qint64 nowMs = nowUTC.toMSecsSinceEpoch(); + const qint64 periodIndex = nowMs / periodMs; + const int periodOffsetMs = nowMs % periodMs; - if (nowUTC.time().second() % 15 < 14) + if (periodOffsetMs < activeWindowMs) { - if (m_tickCount++ == 0) + if (m_lastProcessPeriodIndex != periodIndex) { - QDateTime periodTs = nowUTC.addSecs(-15); - // qDebug("FT8DemodBaseband::tick: %s", qPrintable(nowUTC.toString("yyyy-MM-dd HH:mm:ss"))); - m_ft8Buffer.getCurrentBuffer(m_ft8WorkerBuffer); + const qint64 previousPeriodStartMs = (periodIndex - 1) * periodMs; + QDateTime periodTs = QDateTime::fromMSecsSinceEpoch(previousPeriodStartMs, Qt::UTC); + const int frameSamples = FT8DemodSettings::getDecoderFrameSamples(m_settings.m_decoderMode); + m_ft8Buffer.getCurrentBuffer(m_ft8WorkerBuffer, frameSamples); emit bufferReady(m_ft8WorkerBuffer, periodTs); - periodTs = nowUTC; + m_lastProcessPeriodIndex = periodIndex; } } - else - { - m_tickCount = 0; - } } diff --git a/plugins/channelrx/demodft8/ft8demodbaseband.h b/plugins/channelrx/demodft8/ft8demodbaseband.h index 60142a3b9..df761753b 100644 --- a/plugins/channelrx/demodft8/ft8demodbaseband.h +++ b/plugins/channelrx/demodft8/ft8demodbaseband.h @@ -103,7 +103,7 @@ private: MessageQueue *m_messageQueueToGUI; SpectrumVis *m_spectrumVis; FT8Buffer m_ft8Buffer; - int m_tickCount; + qint64 m_lastProcessPeriodIndex; QThread *m_workerThread; FT8DemodWorker *m_ft8DemodWorker; QThread *m_pskReporterThread; diff --git a/plugins/channelrx/demodft8/ft8demodsettings.cpp b/plugins/channelrx/demodft8/ft8demodsettings.cpp index 75f165448..9f5e717d2 100644 --- a/plugins/channelrx/demodft8/ft8demodsettings.cpp +++ b/plugins/channelrx/demodft8/ft8demodsettings.cpp @@ -50,6 +50,7 @@ void FT8DemodSettings::resetToDefaults() m_agc = false; m_recordWav = false; m_logMessages = false; + m_decoderMode = DecoderModeFT8; m_nbDecoderThreads = 3; m_decoderTimeBudget = 0.5; m_useOSD = false; @@ -78,22 +79,78 @@ void FT8DemodSettings::resetToDefaults() void FT8DemodSettings::resetBandPresets() { - m_bandPresets.clear(); - m_bandPresets.push_back(FT8DemodBandPreset{ "160m", 1840, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "80m", 3573, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "60m", 5357, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "40m", 7074, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "30m", 10136, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "20m", 14074, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "17m", 18100, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "15m", 21074, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "12m", 24915, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "10m", 28074, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "6m", 50313, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "4m", 70100, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "2m", 144120, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{"1.25m", 222065, 0}); - m_bandPresets.push_back(FT8DemodBandPreset{ "70cm", 432065, 0}); + resetBandPresets(m_decoderMode); +} + +void FT8DemodSettings::resetBandPresets(int decoderMode) +{ + m_bandPresets = getBandPresetsForMode(decoderMode); +} + +QList FT8DemodSettings::getBandPresetsForMode(int decoderMode) +{ + QList bandPresets; + + if (decoderMode == DecoderModeFT4) + { + bandPresets.push_back(FT8DemodBandPreset{ "160m", 1840, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "80m", 3575, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "60m", 5357, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "40m", 7047, 500}); + bandPresets.push_back(FT8DemodBandPreset{ "30m", 10140, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "20m", 14080, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "17m", 18104, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "15m", 21140, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "12m", 24919, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "10m", 28180, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "6m", 50318, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "4m", 70154, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "2m", 144170, 0}); + bandPresets.push_back(FT8DemodBandPreset{"1.25m", 222065, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "70cm", 432065, 0}); + } + else + { + bandPresets.push_back(FT8DemodBandPreset{ "160m", 1840, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "80m", 3573, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "60m", 5357, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "40m", 7074, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "30m", 10136, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "20m", 14074, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "17m", 18100, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "15m", 21074, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "12m", 24915, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "10m", 28074, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "6m", 50313, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "4m", 70100, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "2m", 144174, 0}); + bandPresets.push_back(FT8DemodBandPreset{"1.25m", 222065, 0}); + bandPresets.push_back(FT8DemodBandPreset{ "70cm", 432174, 0}); + } + + return bandPresets; +} + +bool FT8DemodSettings::areBandPresetsEqual(const QList& left, const QList& right) +{ + if (left.size() != right.size()) { + return false; + } + + for (int i = 0; i < left.size(); i++) + { + if (left[i].m_name != right[i].m_name) { + return false; + } + if (left[i].m_baseFrequency != right[i].m_baseFrequency) { + return false; + } + if (left[i].m_channelOffset != right[i].m_channelOffset) { + return false; + } + } + + return true; } QByteArray FT8DemodSettings::serialize() const @@ -117,6 +174,7 @@ QByteArray FT8DemodSettings::serialize() const s.writeU32(5, m_rgbColor); s.writeBool(6, m_recordWav); s.writeBool(7, m_logMessages); + s.writeS32(10, m_decoderMode); s.writeS32(8, m_nbDecoderThreads); s.writeFloat(9, m_decoderTimeBudget); s.writeBool(11, m_agc); @@ -190,6 +248,8 @@ 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(10, &m_decoderMode, DecoderModeFT8); + m_decoderMode = (m_decoderMode >= DecoderModeFT8) && (m_decoderMode <= DecoderModeFT4) ? m_decoderMode : DecoderModeFT8; d.readS32(8, &m_nbDecoderThreads, 3); d.readFloat(9, &m_decoderTimeBudget, 0.5); d.readBool(11, &m_agc, false); @@ -269,6 +329,9 @@ void FT8DemodSettings::applySettings(const QStringList& settingsKeys, const FT8D if (settingsKeys.contains("logMessages")) { m_logMessages = settings.m_logMessages; } + if (settingsKeys.contains("decoderMode")) { + m_decoderMode = settings.m_decoderMode; + } if (settingsKeys.contains("nbDecoderThreads")) { m_nbDecoderThreads = settings.m_nbDecoderThreads; } @@ -359,6 +422,9 @@ QString FT8DemodSettings::getDebugString(const QStringList& settingsKeys, bool f if (settingsKeys.contains("logMessages") || force) { ostr << " m_logMessages: " << m_logMessages; } + if (settingsKeys.contains("decoderMode") || force) { + ostr << " m_decoderMode: " << getDecoderModeString(m_decoderMode).toStdString(); + } if (settingsKeys.contains("nbDecoderThreads") || force) { ostr << " m_nbDecoderThreads: " << m_nbDecoderThreads; } @@ -458,3 +524,18 @@ QString FT8DemodSettings::getDefaultReporterSoftware() const { return QCoreApplication::applicationName() + " " + QCoreApplication::applicationVersion(); } + +QString FT8DemodSettings::getDecoderModeString(int decoderMode) +{ + return decoderMode == DecoderModeFT4 ? "FT4" : "FT8"; +} + +int FT8DemodSettings::getDecoderFrameDurationMs(int decoderMode) +{ + return decoderMode == DecoderModeFT4 ? 7500 : 15000; +} + +int FT8DemodSettings::getDecoderFrameSamples(int decoderMode) +{ + return (m_ft8SampleRate * getDecoderFrameDurationMs(decoderMode)) / 1000; +} diff --git a/plugins/channelrx/demodft8/ft8demodsettings.h b/plugins/channelrx/demodft8/ft8demodsettings.h index c3da7b5c8..49253e914 100644 --- a/plugins/channelrx/demodft8/ft8demodsettings.h +++ b/plugins/channelrx/demodft8/ft8demodsettings.h @@ -54,6 +54,11 @@ struct FT8DemodBandPreset class FT8DemodSettings { public: + enum DecoderMode { + DecoderModeFT8, + DecoderModeFT4 + }; + enum MessageCol { MESSAGE_COL_UTC, MESSAGE_COL_TYPE, @@ -76,6 +81,7 @@ public: bool m_agc; bool m_recordWav; bool m_logMessages; + int m_decoderMode; int m_nbDecoderThreads; float m_decoderTimeBudget; bool m_useOSD; @@ -114,11 +120,17 @@ public: QByteArray serialize() const; bool deserialize(const QByteArray& data); void resetBandPresets(); + void resetBandPresets(int decoderMode); QString getDefaultReporterCallsign() const; QString getDefaultReporterLocator() const; QString getDefaultReporterSoftware() const; void applySettings(const QStringList& settingsKeys, const FT8DemodSettings& settings); QString getDebugString(const QStringList& settingsKeys, bool force=false) const; + static QString getDecoderModeString(int decoderMode); + static int getDecoderFrameDurationMs(int decoderMode); + static int getDecoderFrameSamples(int decoderMode); + static QList getBandPresetsForMode(int decoderMode); + static bool areBandPresetsEqual(const QList& left, const QList& right); static const int m_ft8SampleRate; static const int m_minPowerThresholdDB; diff --git a/plugins/channelrx/demodft8/ft8demodsettingsdialog.cpp b/plugins/channelrx/demodft8/ft8demodsettingsdialog.cpp index a64957e96..6505884f7 100644 --- a/plugins/channelrx/demodft8/ft8demodsettingsdialog.cpp +++ b/plugins/channelrx/demodft8/ft8demodsettingsdialog.cpp @@ -27,6 +27,7 @@ FT8DemodSettingsDialog::FT8DemodSettingsDialog(FT8DemodSettings& settings, QStri m_settingsKeys(settingsKeys) { ui->setupUi(this); + ui->decoderMode->setCurrentIndex(m_settings.m_decoderMode); ui->decoderNbThreads->setValue(m_settings.m_nbDecoderThreads); ui->decoderTimeBudget->setValue(m_settings.m_decoderTimeBudget); ui->osdEnable->setChecked(m_settings.m_useOSD); @@ -110,6 +111,33 @@ void FT8DemodSettingsDialog::reject() QDialog::reject(); } +void FT8DemodSettingsDialog::on_decoderMode_currentIndexChanged(int index) +{ + const int previousDecoderMode = m_settings.m_decoderMode; + const QList previousDefaults = FT8DemodSettings::getBandPresetsForMode(previousDecoderMode); + const bool hadDefaultBandPresets = FT8DemodSettings::areBandPresetsEqual(m_settings.m_bandPresets, previousDefaults); + + m_settings.m_decoderMode = (index >= FT8DemodSettings::DecoderModeFT8) && (index <= FT8DemodSettings::DecoderModeFT4) ? + index : FT8DemodSettings::DecoderModeFT8; + + if (hadDefaultBandPresets) + { + m_settings.resetBandPresets(m_settings.m_decoderMode); + ui->bands->blockSignals(true); + ui->bands->setRowCount(0); + populateBandsTable(); + ui->bands->blockSignals(false); + + if (!m_settingsKeys.contains("bandPresets")) { + m_settingsKeys.append("bandPresets"); + } + } + + if (!m_settingsKeys.contains("decoderMode")) { + m_settingsKeys.append("decoderMode"); + } +} + void FT8DemodSettingsDialog::on_decoderNbThreads_valueChanged(int value) { m_settings.m_nbDecoderThreads = value; diff --git a/plugins/channelrx/demodft8/ft8demodsettingsdialog.h b/plugins/channelrx/demodft8/ft8demodsettingsdialog.h index 8dfa03543..0b1b3cad1 100644 --- a/plugins/channelrx/demodft8/ft8demodsettingsdialog.h +++ b/plugins/channelrx/demodft8/ft8demodsettingsdialog.h @@ -54,6 +54,7 @@ private: void setRow(int row, const QList& rowItems); private slots: + void on_decoderMode_currentIndexChanged(int index); void accept(); void reject(); void on_decoderNbThreads_valueChanged(int value); diff --git a/plugins/channelrx/demodft8/ft8demodsettingsdialog.ui b/plugins/channelrx/demodft8/ft8demodsettingsdialog.ui index fde012213..a455a0f8e 100644 --- a/plugins/channelrx/demodft8/ft8demodsettingsdialog.ui +++ b/plugins/channelrx/demodft8/ft8demodsettingsdialog.ui @@ -27,6 +27,47 @@ + + + + + Mode + + + + + + + Decoder mode. FT4 timing and reporting are wired, decoding support is pending. + + + + FT8 + + + + + FT4 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + diff --git a/plugins/channelrx/demodft8/ft8demodworker.cpp b/plugins/channelrx/demodft8/ft8demodworker.cpp index a44563385..2e9ef9810 100644 --- a/plugins/channelrx/demodft8/ft8demodworker.cpp +++ b/plugins/channelrx/demodft8/ft8demodworker.cpp @@ -145,12 +145,14 @@ FT8DemodWorker::FT8DemodWorker() : m_enablePskReporter(false), m_nbDecoderThreads(6), m_decoderTimeBudget(0.5), + m_decoderMode(FT8DemodSettings::DecoderModeFT8), m_useOSD(false), m_osdDepth(0), m_osdLDPCThreshold(70), m_verifyOSD(false), m_lowFreq(200), m_highFreq(3000), + m_unsupportedModeWarningPending(true), m_invalidSequence(true), m_baseFrequency(0), m_guiReportingMessageQueue(nullptr), @@ -180,11 +182,21 @@ FT8DemodWorker::FT8DemodWorker() : FT8DemodWorker::~FT8DemodWorker() {} +void FT8DemodWorker::setDecoderMode(int decoderMode) +{ + m_decoderMode = decoderMode; + m_unsupportedModeWarningPending = true; +} + void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) { - qDebug("FT8DemodWorker::processBuffer: %6.3f %s %d:%f [%d:%d]", + const int frameSampleCount = FT8DemodSettings::getDecoderFrameSamples(m_decoderMode); + const QString decoderMode = FT8DemodSettings::getDecoderModeString(m_decoderMode); + + qDebug("FT8DemodWorker::processBuffer: %6.3f %s mode:%s %d:%f [%d:%d]", m_baseFrequency / 1000000.0, qPrintable(periodTS.toString("yyyy-MM-dd HH:mm:ss")), + qPrintable(decoderMode), m_nbDecoderThreads, m_decoderTimeBudget, m_lowFreq, @@ -198,6 +210,32 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) return; } + if (m_decoderMode != FT8DemodSettings::DecoderModeFT8) + { + if (m_unsupportedModeWarningPending) + { + qWarning("FT8DemodWorker::processBuffer: %s decoding is not implemented yet", qPrintable(decoderMode)); + m_unsupportedModeWarningPending = false; + } + + 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, frameSampleCount); + wavFileRecord->stopRecording(); + delete wavFileRecord; + } + + return; + } + QString channelReference = "d0c0"; // default if (m_channel) { @@ -211,11 +249,11 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) m_ft8Decoder.getParams().use_osd = m_useOSD ? 1 : 0; m_ft8Decoder.getParams().osd_depth = m_osdDepth; m_ft8Decoder.getParams().osd_ldpc_thresh = m_osdLDPCThreshold; - std::vector samples(15*FT8DemodSettings::m_ft8SampleRate); + std::vector samples(frameSampleCount); std::transform( buffer, - buffer + (15*FT8DemodSettings::m_ft8SampleRate), + buffer + frameSampleCount, samples.begin(), [](const int16_t& s) -> float { return s / 32768.0f; } ); @@ -275,9 +313,10 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) continue; } - QString logMessage = QString("%1 %2 Rx FT8 %3 %4 %5 %6 %7 %8") + QString logMessage = QString("%1 %2 Rx %3 %4 %5 %6 %7 %8 %9") .arg(periodTS.toString("yyyyMMdd_HHmmss")) .arg(baseFrequencyMHz, 9, 'f', 3) + .arg(decoderMode) .arg(ft8Message.snr, 6) .arg(ft8Message.dt, 4, 'f', 1) .arg(ft8Message.df, 4, 'f', 0) @@ -301,8 +340,9 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) if ((ft8Message.loc.size() == 4) && (ft8Message.loc != "RR73") && Maidenhead::fromMaidenhead(ft8Message.loc, latitude, longitude)) { - QString text = QString("%1\nMode: FT8\nFrequency: %2 Hz\nLocator: %3\nSNR: %4\nLast heard: %5") + QString text = QString("%1\nMode: %2\nFrequency: %3 Hz\nLocator: %4\nSNR: %5\nLast heard: %6") .arg(ft8Message.call2) + .arg(decoderMode) .arg(baseFrequencyMHz*1000000 + ft8Message.df) .arg(ft8Message.loc) .arg(ft8Message.snr) @@ -361,7 +401,7 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) wavFileRecord->setFileBaseIsFileName(true); wavFileRecord->setMono(true); wavFileRecord->startRecording(); - wavFileRecord->writeMono(buffer, 15*FT8DemodSettings::m_ft8SampleRate); + wavFileRecord->writeMono(buffer, frameSampleCount); wavFileRecord->stopRecording(); delete wavFileRecord; } diff --git a/plugins/channelrx/demodft8/ft8demodworker.h b/plugins/channelrx/demodft8/ft8demodworker.h index 6e0229032..28c34baa7 100644 --- a/plugins/channelrx/demodft8/ft8demodworker.h +++ b/plugins/channelrx/demodft8/ft8demodworker.h @@ -44,6 +44,7 @@ public: void setEnablePskReporter(bool enablePskReporter) { m_enablePskReporter = enablePskReporter; } void setNbDecoderThreads(int nbDecoderThreads) { m_nbDecoderThreads = nbDecoderThreads; } void setDecoderTimeBudget(float decoderTimeBudget) { m_decoderTimeBudget = decoderTimeBudget; } + void setDecoderMode(int decoderMode); void setUseOSD(bool useOSD) { m_useOSD = useOSD; } void setOSDDepth(int osdDepth) { m_osdDepth = osdDepth; } void setOSDLDPCThreshold(int osdLDPCThreshold) { m_osdLDPCThreshold = osdLDPCThreshold; } @@ -97,12 +98,14 @@ private: bool m_enablePskReporter; int m_nbDecoderThreads; float m_decoderTimeBudget; + int m_decoderMode; bool m_useOSD; int m_osdDepth; int m_osdLDPCThreshold; bool m_verifyOSD; int m_lowFreq; int m_highFreq; + bool m_unsupportedModeWarningPending; bool m_invalidSequence; qint64 m_baseFrequency; FT8::FT8Decoder m_ft8Decoder; diff --git a/plugins/channelrx/demodft8/pskreporterworker.cpp b/plugins/channelrx/demodft8/pskreporterworker.cpp index d451bb09d..154eeea1e 100644 --- a/plugins/channelrx/demodft8/pskreporterworker.cpp +++ b/plugins/channelrx/demodft8/pskreporterworker.cpp @@ -23,7 +23,6 @@ const char PskReporterWorker::hostname[] = "report.pskreporter.info"; const char PskReporterWorker::service[] = "4739"; const char PskReporterWorker::test_service[] = "14739"; -const char PskReporterWorker::txMode[] = "FT8"; const unsigned char PskReporterWorker::rxDescriptor[] = { 0x00, 0x03, // Template Set ID 0x00, 0x24, // Length @@ -69,6 +68,7 @@ const unsigned char PskReporterWorker::txDescriptor[] = { }; // "PSKREPORTER_TX" PskReporterWorker::PskReporterWorker() : + m_txMode("FT8"), m_udpSocket(new QUdpSocket(this)) { connect(&m_reportQueue, &MessageQueue::messageEnqueued, @@ -126,10 +126,11 @@ void PskReporterWorker::processFT8Messages(const QList& ft8Messages, txPtr +=1; // Station Mode - const size_t modeLen = strlen(txMode); + const QByteArray txMode = m_txMode.toUtf8(); + const size_t modeLen = txMode.size(); *(uint8_t *)&txInfoData[txPtr] = (uint8_t)modeLen; txPtr += 1; - memcpy(&txInfoData[txPtr], txMode, modeLen); + memcpy(&txInfoData[txPtr], txMode.constData(), modeLen); txPtr += modeLen; // Station locator diff --git a/plugins/channelrx/demodft8/pskreporterworker.h b/plugins/channelrx/demodft8/pskreporterworker.h index f6dc4c2cb..637cb6126 100644 --- a/plugins/channelrx/demodft8/pskreporterworker.h +++ b/plugins/channelrx/demodft8/pskreporterworker.h @@ -39,6 +39,7 @@ public: void setMyCallsign(const QString& callsign) { m_myCallsign = callsign; } void setMyLocator(const QString& locator) { m_myLocator = locator; } void setDecoderInfo(const QString& decoderInfo) { m_decoderInfo = decoderInfo; } + void setTxMode(const QString& txMode) { m_txMode = txMode; } void setTestMode(bool isTestMode) { m_isTestMode = isTestMode; } private: @@ -52,6 +53,7 @@ private: QString m_myCallsign; QString m_myLocator; QString m_decoderInfo; + QString m_txMode; bool m_isTestMode = false; MessageQueue m_reportQueue; QQueue m_ft8MessageQueue; @@ -66,7 +68,6 @@ private: static const char hostname[]; static const char service[]; static const char test_service[]; - static const char txMode[]; static const unsigned char rxDescriptor[]; static const unsigned char txDescriptor[];