diff --git a/ft8/fft.cpp b/ft8/fft.cpp index 2cfec06a6..b96993f92 100644 --- a/ft8/fft.cpp +++ b/ft8/fft.cpp @@ -33,19 +33,19 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why) // cache fftw plans in the parent process, // so they will already be there for fork()ed children. - plansmu.lock(); + m_plansmu.lock(); - for (int i = 0; i < nplans; i++) + for (int i = 0; i < m_nplans; i++) { - if (plans[i]->n_ == n && plans[i]->type_ == fftw_type + if (m_plans[i]->n_ == n && m_plans[i]->type_ == M_FFTW_TYPE #if TIMING && strcmp(plans[i]->why_, why) == 0 #endif ) { - Plan *p = plans[i]; + Plan *p = m_plans[i]; p->uses_ += 1; - plansmu.unlock(); + m_plansmu.unlock(); return p; } } @@ -55,7 +55,7 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why) #endif // fftw_make_planner_thread_safe(); - plansmu2.lock(); + m_plansmu2.lock(); fftwf_set_timelimit(5); @@ -80,7 +80,7 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why) // FFTW_MEASURE // FFTW_PATIENT // FFTW_EXHAUSTIVE - int type = fftw_type; + int type = M_FFTW_TYPE; p->type_ = type; p->fwd_ = fftwf_plan_dft_r2c_1d(n, p->r_, p->c_, type); assert(p->fwd_); @@ -99,12 +99,12 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why) p->crev_ = fftwf_plan_dft_1d(n, p->cc2_, p->cc1_, FFTW_BACKWARD, type); assert(p->crev_); - plansmu2.unlock(); + m_plansmu2.unlock(); - assert(nplans + 1 < 1000); + assert(m_nplans + 1 < 1000); - plans[nplans] = p; - nplans += 1; + m_plans[m_nplans] = p; + m_nplans += 1; #if TIMING if (0 && getpid() == plan_master_pid) @@ -115,7 +115,7 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why) } #endif - plansmu.unlock(); + m_plansmu.unlock(); return p; } @@ -562,9 +562,9 @@ std::vector FFTEngine::hilbert_shift(const std::vector &x, float h void FFTEngine::fft_stats() { - for (int i = 0; i < nplans; i++) + for (int i = 0; i < m_nplans; i++) { - Plan *p = plans[i]; + Plan *p = m_plans[i]; qDebug("FT8::FFTEngine::fft_stats: %-13s %6d %9d %6.3fn", p->why_, p->n_, diff --git a/ft8/fft.h b/ft8/fft.h index cbd713f17..ffb38e3f4 100644 --- a/ft8/fft.h +++ b/ft8/fft.h @@ -67,7 +67,7 @@ public: int uses_; }; // Plan - FFTEngine() : nplans(0) + FFTEngine() : m_nplans(0) {} Plan *get_plan(int n, const char *why); @@ -84,12 +84,12 @@ public: private: void fft_stats(); - QMutex plansmu; - QMutex plansmu2; - Plan *plans[1000]; - int nplans; + QMutex m_plansmu; + QMutex m_plansmu2; + Plan *m_plans[1000]; + int m_nplans; // MEASURE=0, ESTIMATE=64, PATIENT=32 - static const int fftw_type = FFTW_ESTIMATE; + static const int M_FFTW_TYPE = FFTW_ESTIMATE; }; // FFTEngine } // namespace FT8 diff --git a/plugins/channelrx/demodft8/ft8demodbaseband.cpp b/plugins/channelrx/demodft8/ft8demodbaseband.cpp index ee7e694bb..86f0395cf 100644 --- a/plugins/channelrx/demodft8/ft8demodbaseband.cpp +++ b/plugins/channelrx/demodft8/ft8demodbaseband.cpp @@ -102,6 +102,7 @@ void FT8DemodBaseband::setMessageQueueToGUI(MessageQueue *messageQueue) void FT8DemodBaseband::setChannel(ChannelAPI *channel) { m_sink.setChannel(channel); + m_ft8DemodWorker->setChannel(channel); } void FT8DemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) @@ -184,6 +185,7 @@ bool FT8DemodBaseband::handleMessage(const Message& cmd) { m_ft8DemodWorker->invalidateSequence(); m_deviceCenterFrequency = notif.getCenterFrequency(); + m_ft8DemodWorker->setBaseFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset); } return true; @@ -199,6 +201,7 @@ void FT8DemodBaseband::applySettings(const FT8DemodSettings& settings, bool forc if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force) { m_ft8DemodWorker->invalidateSequence(); + m_ft8DemodWorker->setBaseFrequency(m_deviceCenterFrequency + settings.m_inputFrequencyOffset); m_channelizer.setChannelization(FT8DemodSettings::m_ft8SampleRate, settings.m_inputFrequencyOffset); m_sink.applyChannelSettings(m_channelizer.getChannelSampleRate(), m_channelizer.getChannelFrequencyOffset()); diff --git a/plugins/channelrx/demodft8/ft8demodgui.cpp b/plugins/channelrx/demodft8/ft8demodgui.cpp index b8682eb85..782947034 100644 --- a/plugins/channelrx/demodft8/ft8demodgui.cpp +++ b/plugins/channelrx/demodft8/ft8demodgui.cpp @@ -622,7 +622,7 @@ void FT8DemodGUI::resizeMessageTable() 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_CALL2, new QTableWidgetItem("PA900RAALTE")); ui->messages->setItem(row, MESSAGE_COL_LOC, new QTableWidgetItem("JN000")); ui->messages->setItem(row, MESSAGE_COL_INFO, new QTableWidgetItem("OSD-0-73")); ui->messages->resizeColumnsToContents(); @@ -668,10 +668,10 @@ void FT8DemodGUI::messagesReceived(const QList& messages) utcItem->setText(message.ts.toString("HHmmss")); passItem->setText(tr("%1").arg(message.pass)); - snrItem->setText(tr("%1").arg(message.snr)); correctItem->setText(tr("%1").arg(message.nbCorrectBits)); - dtItem->setText(tr("%1").arg(message.dt, 0, 'f', 1)); - dfItem->setText(tr("%1").arg((int) message.df)); + dtItem->setText(tr("%1").arg(message.dt, 4, 'f', 1)); + dfItem->setText(tr("%1").arg((int) message.df, 4)); + snrItem->setText(tr("%1").arg(message.snr, 3)); call1Item->setText(message.call1); call2Item->setText(message.call2); locItem->setText(message.loc); diff --git a/plugins/channelrx/demodft8/ft8demodgui.h b/plugins/channelrx/demodft8/ft8demodgui.h index 590f242a0..d63aa9003 100644 --- a/plugins/channelrx/demodft8/ft8demodgui.h +++ b/plugins/channelrx/demodft8/ft8demodgui.h @@ -107,10 +107,10 @@ private: enum MessageCol { MESSAGE_COL_UTC, MESSAGE_COL_N, - MESSAGE_COL_SNR, MESSAGE_COL_DEC, MESSAGE_COL_DT, MESSAGE_COL_DF, + MESSAGE_COL_SNR, MESSAGE_COL_CALL1, MESSAGE_COL_CALL2, MESSAGE_COL_LOC, diff --git a/plugins/channelrx/demodft8/ft8demodgui.ui b/plugins/channelrx/demodft8/ft8demodgui.ui index e49166cbc..ba75ff30c 100644 --- a/plugins/channelrx/demodft8/ft8demodgui.ui +++ b/plugins/channelrx/demodft8/ft8demodgui.ui @@ -6,7 +6,7 @@ 0 0 - 500 + 520 731 @@ -18,7 +18,7 @@ - 500 + 520 0 @@ -36,7 +36,7 @@ 0 0 - 481 + 501 181 @@ -742,7 +742,7 @@ 0 460 - 481 + 501 251 @@ -965,12 +965,24 @@ + + + Liberation Mono + 9 + + Decoded messages QAbstractItemView::NoEditTriggers + + 15 + + + 15 + UTC @@ -987,14 +999,6 @@ Successful decoder pass index - - - SNR - - - Signal to noise ratio (dB) in 2.5 kHz bandwidth - - OKb @@ -1019,6 +1023,14 @@ Frequency shift + + + SNR + + + Signal to noise ratio (dB) in 2.5 kHz bandwidth + + Call1 diff --git a/plugins/channelrx/demodft8/ft8demodworker.cpp b/plugins/channelrx/demodft8/ft8demodworker.cpp index feabd68fc..c4088341b 100644 --- a/plugins/channelrx/demodft8/ft8demodworker.cpp +++ b/plugins/channelrx/demodft8/ft8demodworker.cpp @@ -19,6 +19,7 @@ #include #include +#include "channel/channelapi.h" #include "dsp/wavfilerecord.h" #include "util/messagequeue.h" #include "util/ft8message.h" @@ -26,11 +27,13 @@ #include "ft8demodsettings.h" #include "ft8demodworker.h" -FT8DemodWorker::FT8Callback::FT8Callback(const QDateTime& periodTS, FT8::Packing& packing) : +FT8DemodWorker::FT8Callback::FT8Callback(const QDateTime& periodTS, qint64 baseFrequency, FT8::Packing& packing) : m_packing(packing), - m_periodTS(periodTS) + m_periodTS(periodTS), + m_baseFrequency(baseFrequency) { m_msgReportFT8Messages = MsgReportFT8Messages::create(); + m_msgReportFT8Messages->setBaseFrequency(baseFrequency); } int FT8DemodWorker::FT8Callback::hcb( @@ -69,22 +72,20 @@ int FT8DemodWorker::FT8Callback::hcb( 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.call1 = QString(call1.c_str()).simplified(); + ft8Message.call2 = QString(call2.c_str()).simplified(); + ft8Message.loc = QString(loc.c_str()).simplified(); ft8Message.decoderInfo = QString(comment); cycle_mu.unlock(); - qDebug("FT8DemodWorker::FT8Callback::hcb: %d %3d %3d %5.2f %6.1f %s [%s:%s:%s] (%s)", + qDebug("FT8DemodWorker::FT8Callback::hcb: %6.3f %d %3d %3d %5.2f %6.1f %s (%s)", + m_baseFrequency / 1000000.0, pass, (int)snr, correct_bits, off - 0.5, hz0, msg.c_str(), - call1.c_str(), - call2.c_str(), - loc.c_str(), comment ); @@ -97,13 +98,19 @@ FT8DemodWorker::FT8DemodWorker() : m_decoderTimeBudget(0.5), m_lowFreq(200), m_highFreq(3000), - m_reportingMessageQueue(nullptr) + m_invalidSequence(true), + m_baseFrequency(0), + m_reportingMessageQueue(nullptr), + m_channel(nullptr) { QString relPath = "sdrangel/ft8/save"; QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)); dir.mkpath(relPath); m_samplesPath = dir.absolutePath() + "/" + relPath; qDebug("FT8DemodWorker::FT8DemodWorker: samples path: %s", qPrintable(m_samplesPath)); + relPath = "sdrangel/ft8"; + m_logsPath = dir.absolutePath() + "/" + relPath; + qDebug("FT8DemodWorker::FT8DemodWorker: logs path: %s", qPrintable(m_logsPath)); } FT8DemodWorker::~FT8DemodWorker() @@ -111,8 +118,14 @@ FT8DemodWorker::~FT8DemodWorker() void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) { - 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); + qDebug("FT8DemodWorker::processBuffer: %6.3f %s %d:%f [%d:%d]", + m_baseFrequency / 1000000.0, + qPrintable(periodTS.toString("yyyy-MM-dd HH:mm:ss")), + m_nbDecoderThreads, + m_decoderTimeBudget, + m_lowFreq, + m_highFreq + ); if (m_invalidSequence) { @@ -121,23 +134,8 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) return; } - 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); + FT8Callback ft8Callback(periodTS, m_baseFrequency, m_packing); m_ft8Decoder.getParams().nthreads = m_nbDecoderThreads; std::vector samples(15*FT8DemodSettings::m_ft8SampleRate); @@ -165,11 +163,78 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS) ); 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()); + qDebug("FT8DemodWorker::processBuffer: done: at %6.3f %d messages", + m_baseFrequency / 1000000.0, ft8Callback.getReportMessage()->getFT8Messages().size()); if (m_reportingMessageQueue) { m_reportingMessageQueue->push(ft8Callback.getReportMessage()); - } else { - delete ft8Callback.getReportMessage(); + } + + if (m_logMessages) + { + const QList& ft8Messages = ft8Callback.getReportMessage()->getFT8Messages(); + std::ofstream logFile; + double baseFrequencyMHz = m_baseFrequency/1000000.0; + + for (const auto& ft8Message : ft8Messages) + { + if (!logFile.is_open()) + { + QString channelReference = "d0c0"; // default + + if (m_channel) { + channelReference = tr("d%1c%2").arg(m_channel->getDeviceSetIndex()).arg(m_channel->getIndexInDeviceSet()); + } + + QString logFileName(tr("%1_%2.txt").arg(periodTS.toString("yyyyMMdd")).arg(channelReference)); + QFileInfo lfi(QDir(m_logsPath), logFileName); + QString logFilePath = lfi.absoluteFilePath(); + + if (lfi.exists()) { + logFile.open(logFilePath.toStdString(), std::ios::app); + } else { + logFile.open(logFilePath.toStdString()); + } + } + + if (ft8Message.call1 == "UNK") { + continue; + } + + QString logMessage = QString("%1 %2 Rx FT8 %3 %4 %5 %6 %7 %8") + .arg(ft8Message.ts.toString("yyyyMMdd_HHmmss")) + .arg(baseFrequencyMHz, 9, 'f', 3) + .arg(ft8Message.snr, 6) + .arg(ft8Message.dt, 4, 'f', 1) + .arg(ft8Message.df, 4, 'f', 0) + .arg(ft8Message.call1) + .arg(ft8Message.call2) + .arg(ft8Message.loc); + logMessage.remove(0, 2); + logFile << logMessage.toStdString() << std::endl; + } + + if (logFile.is_open()) { + logFile.close(); + } + } + + if (!m_reportingMessageQueue) { + delete m_reportingMessageQueue; + } + + 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; } } diff --git a/plugins/channelrx/demodft8/ft8demodworker.h b/plugins/channelrx/demodft8/ft8demodworker.h index bb0eed212..bace69dd5 100644 --- a/plugins/channelrx/demodft8/ft8demodworker.h +++ b/plugins/channelrx/demodft8/ft8demodworker.h @@ -26,6 +26,7 @@ class QDateTime; class MessageQueue; class MsgReportFT8Messages; +class ChannelAPI; class FT8DemodWorker : public QObject { @@ -43,12 +44,14 @@ public: void setHighFrequency(int highFreq) { m_highFreq = highFreq; } void setReportingMessageQueue(MessageQueue *messageQueue) { m_reportingMessageQueue = messageQueue; } void invalidateSequence() { m_invalidSequence = true; } + void setBaseFrequency(qint64 baseFrequency) { m_baseFrequency = baseFrequency; } + void setChannel(ChannelAPI *channel) { m_channel = channel; } private: class FT8Callback : public FT8::CallbackInterface { public: - FT8Callback(const QDateTime& periodTS, FT8::Packing& packing); + FT8Callback(const QDateTime& periodTS, qint64 baseFrequency, FT8::Packing& packing); virtual int hcb( int *a91, float hz0, @@ -58,21 +61,20 @@ private: int pass, int correct_bits ); - const std::map& getMsgMap() { - return cycle_already; - } - MsgReportFT8Messages *getReportMessage() { - return m_msgReportFT8Messages; - } + 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; + qint64 m_baseFrequency; }; QString m_samplesPath; + QString m_logsPath; bool m_recordSamples; bool m_logMessages; int m_nbDecoderThreads; @@ -80,9 +82,11 @@ private: int m_lowFreq; int m_highFreq; bool m_invalidSequence; + qint64 m_baseFrequency; FT8::FT8Decoder m_ft8Decoder; FT8::Packing m_packing; MessageQueue *m_reportingMessageQueue; + ChannelAPI *m_channel; }; #endif // INCLUDE_FT8DEMODWORKER_H diff --git a/sdrbase/util/ft8message.h b/sdrbase/util/ft8message.h index 151147056..a951d0522 100644 --- a/sdrbase/util/ft8message.h +++ b/sdrbase/util/ft8message.h @@ -42,6 +42,7 @@ class FT8_API MsgReportFT8Messages : public Message { MESSAGE_CLASS_DECLARATION public: QList& getFT8Messages() { return m_ft8Messages; } + void setBaseFrequency(qint64 baseFrequency) { m_baseFrequency = baseFrequency; } static MsgReportFT8Messages* create() { return new MsgReportFT8Messages(); @@ -49,9 +50,11 @@ public: private: QList m_ft8Messages; + qint64 m_baseFrequency; MsgReportFT8Messages() : - Message() + Message(), + m_baseFrequency(0) { } };