mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-25 09:18:54 -05:00
FT8 demod: implemented logging and GUI updates
This commit is contained in:
parent
d4363929f4
commit
6c15a0ffd2
28
ft8/fft.cpp
28
ft8/fft.cpp
@ -33,19 +33,19 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why)
|
|||||||
// cache fftw plans in the parent process,
|
// cache fftw plans in the parent process,
|
||||||
// so they will already be there for fork()ed children.
|
// 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
|
#if TIMING
|
||||||
&& strcmp(plans[i]->why_, why) == 0
|
&& strcmp(plans[i]->why_, why) == 0
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Plan *p = plans[i];
|
Plan *p = m_plans[i];
|
||||||
p->uses_ += 1;
|
p->uses_ += 1;
|
||||||
plansmu.unlock();
|
m_plansmu.unlock();
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,7 +55,7 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// fftw_make_planner_thread_safe();
|
// fftw_make_planner_thread_safe();
|
||||||
plansmu2.lock();
|
m_plansmu2.lock();
|
||||||
|
|
||||||
fftwf_set_timelimit(5);
|
fftwf_set_timelimit(5);
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why)
|
|||||||
// FFTW_MEASURE
|
// FFTW_MEASURE
|
||||||
// FFTW_PATIENT
|
// FFTW_PATIENT
|
||||||
// FFTW_EXHAUSTIVE
|
// FFTW_EXHAUSTIVE
|
||||||
int type = fftw_type;
|
int type = M_FFTW_TYPE;
|
||||||
p->type_ = type;
|
p->type_ = type;
|
||||||
p->fwd_ = fftwf_plan_dft_r2c_1d(n, p->r_, p->c_, type);
|
p->fwd_ = fftwf_plan_dft_r2c_1d(n, p->r_, p->c_, type);
|
||||||
assert(p->fwd_);
|
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);
|
p->crev_ = fftwf_plan_dft_1d(n, p->cc2_, p->cc1_, FFTW_BACKWARD, type);
|
||||||
assert(p->crev_);
|
assert(p->crev_);
|
||||||
|
|
||||||
plansmu2.unlock();
|
m_plansmu2.unlock();
|
||||||
|
|
||||||
assert(nplans + 1 < 1000);
|
assert(m_nplans + 1 < 1000);
|
||||||
|
|
||||||
plans[nplans] = p;
|
m_plans[m_nplans] = p;
|
||||||
nplans += 1;
|
m_nplans += 1;
|
||||||
|
|
||||||
#if TIMING
|
#if TIMING
|
||||||
if (0 && getpid() == plan_master_pid)
|
if (0 && getpid() == plan_master_pid)
|
||||||
@ -115,7 +115,7 @@ FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
plansmu.unlock();
|
m_plansmu.unlock();
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -562,9 +562,9 @@ std::vector<float> FFTEngine::hilbert_shift(const std::vector<float> &x, float h
|
|||||||
|
|
||||||
void FFTEngine::fft_stats()
|
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",
|
qDebug("FT8::FFTEngine::fft_stats: %-13s %6d %9d %6.3fn",
|
||||||
p->why_,
|
p->why_,
|
||||||
p->n_,
|
p->n_,
|
||||||
|
12
ft8/fft.h
12
ft8/fft.h
@ -67,7 +67,7 @@ public:
|
|||||||
int uses_;
|
int uses_;
|
||||||
}; // Plan
|
}; // Plan
|
||||||
|
|
||||||
FFTEngine() : nplans(0)
|
FFTEngine() : m_nplans(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Plan *get_plan(int n, const char *why);
|
Plan *get_plan(int n, const char *why);
|
||||||
@ -84,12 +84,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void fft_stats();
|
void fft_stats();
|
||||||
QMutex plansmu;
|
QMutex m_plansmu;
|
||||||
QMutex plansmu2;
|
QMutex m_plansmu2;
|
||||||
Plan *plans[1000];
|
Plan *m_plans[1000];
|
||||||
int nplans;
|
int m_nplans;
|
||||||
// MEASURE=0, ESTIMATE=64, PATIENT=32
|
// MEASURE=0, ESTIMATE=64, PATIENT=32
|
||||||
static const int fftw_type = FFTW_ESTIMATE;
|
static const int M_FFTW_TYPE = FFTW_ESTIMATE;
|
||||||
}; // FFTEngine
|
}; // FFTEngine
|
||||||
|
|
||||||
} // namespace FT8
|
} // namespace FT8
|
||||||
|
@ -102,6 +102,7 @@ void FT8DemodBaseband::setMessageQueueToGUI(MessageQueue *messageQueue)
|
|||||||
void FT8DemodBaseband::setChannel(ChannelAPI *channel)
|
void FT8DemodBaseband::setChannel(ChannelAPI *channel)
|
||||||
{
|
{
|
||||||
m_sink.setChannel(channel);
|
m_sink.setChannel(channel);
|
||||||
|
m_ft8DemodWorker->setChannel(channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FT8DemodBaseband::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end)
|
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_ft8DemodWorker->invalidateSequence();
|
||||||
m_deviceCenterFrequency = notif.getCenterFrequency();
|
m_deviceCenterFrequency = notif.getCenterFrequency();
|
||||||
|
m_ft8DemodWorker->setBaseFrequency(m_deviceCenterFrequency + m_settings.m_inputFrequencyOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -199,6 +201,7 @@ void FT8DemodBaseband::applySettings(const FT8DemodSettings& settings, bool forc
|
|||||||
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
|
if ((settings.m_inputFrequencyOffset != m_settings.m_inputFrequencyOffset) || force)
|
||||||
{
|
{
|
||||||
m_ft8DemodWorker->invalidateSequence();
|
m_ft8DemodWorker->invalidateSequence();
|
||||||
|
m_ft8DemodWorker->setBaseFrequency(m_deviceCenterFrequency + settings.m_inputFrequencyOffset);
|
||||||
m_channelizer.setChannelization(FT8DemodSettings::m_ft8SampleRate, settings.m_inputFrequencyOffset);
|
m_channelizer.setChannelization(FT8DemodSettings::m_ft8SampleRate, settings.m_inputFrequencyOffset);
|
||||||
m_sink.applyChannelSettings(m_channelizer.getChannelSampleRate(), m_channelizer.getChannelFrequencyOffset());
|
m_sink.applyChannelSettings(m_channelizer.getChannelSampleRate(), m_channelizer.getChannelFrequencyOffset());
|
||||||
|
|
||||||
|
@ -622,7 +622,7 @@ void FT8DemodGUI::resizeMessageTable()
|
|||||||
ui->messages->setItem(row, MESSAGE_COL_DT, new QTableWidgetItem("-0.0"));
|
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_DF, new QTableWidgetItem("0000"));
|
||||||
ui->messages->setItem(row, MESSAGE_COL_CALL1, new QTableWidgetItem("123456789ABCD"));
|
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_LOC, new QTableWidgetItem("JN000"));
|
||||||
ui->messages->setItem(row, MESSAGE_COL_INFO, new QTableWidgetItem("OSD-0-73"));
|
ui->messages->setItem(row, MESSAGE_COL_INFO, new QTableWidgetItem("OSD-0-73"));
|
||||||
ui->messages->resizeColumnsToContents();
|
ui->messages->resizeColumnsToContents();
|
||||||
@ -668,10 +668,10 @@ void FT8DemodGUI::messagesReceived(const QList<FT8Message>& messages)
|
|||||||
|
|
||||||
utcItem->setText(message.ts.toString("HHmmss"));
|
utcItem->setText(message.ts.toString("HHmmss"));
|
||||||
passItem->setText(tr("%1").arg(message.pass));
|
passItem->setText(tr("%1").arg(message.pass));
|
||||||
snrItem->setText(tr("%1").arg(message.snr));
|
|
||||||
correctItem->setText(tr("%1").arg(message.nbCorrectBits));
|
correctItem->setText(tr("%1").arg(message.nbCorrectBits));
|
||||||
dtItem->setText(tr("%1").arg(message.dt, 0, 'f', 1));
|
dtItem->setText(tr("%1").arg(message.dt, 4, 'f', 1));
|
||||||
dfItem->setText(tr("%1").arg((int) message.df));
|
dfItem->setText(tr("%1").arg((int) message.df, 4));
|
||||||
|
snrItem->setText(tr("%1").arg(message.snr, 3));
|
||||||
call1Item->setText(message.call1);
|
call1Item->setText(message.call1);
|
||||||
call2Item->setText(message.call2);
|
call2Item->setText(message.call2);
|
||||||
locItem->setText(message.loc);
|
locItem->setText(message.loc);
|
||||||
|
@ -107,10 +107,10 @@ private:
|
|||||||
enum MessageCol {
|
enum MessageCol {
|
||||||
MESSAGE_COL_UTC,
|
MESSAGE_COL_UTC,
|
||||||
MESSAGE_COL_N,
|
MESSAGE_COL_N,
|
||||||
MESSAGE_COL_SNR,
|
|
||||||
MESSAGE_COL_DEC,
|
MESSAGE_COL_DEC,
|
||||||
MESSAGE_COL_DT,
|
MESSAGE_COL_DT,
|
||||||
MESSAGE_COL_DF,
|
MESSAGE_COL_DF,
|
||||||
|
MESSAGE_COL_SNR,
|
||||||
MESSAGE_COL_CALL1,
|
MESSAGE_COL_CALL1,
|
||||||
MESSAGE_COL_CALL2,
|
MESSAGE_COL_CALL2,
|
||||||
MESSAGE_COL_LOC,
|
MESSAGE_COL_LOC,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>500</width>
|
<width>520</width>
|
||||||
<height>731</height>
|
<height>731</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -18,7 +18,7 @@
|
|||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>500</width>
|
<width>520</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>481</width>
|
<width>501</width>
|
||||||
<height>181</height>
|
<height>181</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -742,7 +742,7 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>460</y>
|
<y>460</y>
|
||||||
<width>481</width>
|
<width>501</width>
|
||||||
<height>251</height>
|
<height>251</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
@ -965,12 +965,24 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QTableWidget" name="messages">
|
<widget class="QTableWidget" name="messages">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<family>Liberation Mono</family>
|
||||||
|
<pointsize>9</pointsize>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Decoded messages</string>
|
<string>Decoded messages</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="editTriggers">
|
<property name="editTriggers">
|
||||||
<set>QAbstractItemView::NoEditTriggers</set>
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
</property>
|
</property>
|
||||||
|
<attribute name="verticalHeaderMinimumSectionSize">
|
||||||
|
<number>15</number>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="verticalHeaderDefaultSectionSize">
|
||||||
|
<number>15</number>
|
||||||
|
</attribute>
|
||||||
<column>
|
<column>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>UTC</string>
|
<string>UTC</string>
|
||||||
@ -987,14 +999,6 @@
|
|||||||
<string>Successful decoder pass index</string>
|
<string>Successful decoder pass index</string>
|
||||||
</property>
|
</property>
|
||||||
</column>
|
</column>
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>SNR</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Signal to noise ratio (dB) in 2.5 kHz bandwidth</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
<column>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>OKb</string>
|
<string>OKb</string>
|
||||||
@ -1019,6 +1023,14 @@
|
|||||||
<string>Frequency shift</string>
|
<string>Frequency shift</string>
|
||||||
</property>
|
</property>
|
||||||
</column>
|
</column>
|
||||||
|
<column>
|
||||||
|
<property name="text">
|
||||||
|
<string>SNR</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Signal to noise ratio (dB) in 2.5 kHz bandwidth</string>
|
||||||
|
</property>
|
||||||
|
</column>
|
||||||
<column>
|
<column>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Call1</string>
|
<string>Call1</string>
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "channel/channelapi.h"
|
||||||
#include "dsp/wavfilerecord.h"
|
#include "dsp/wavfilerecord.h"
|
||||||
#include "util/messagequeue.h"
|
#include "util/messagequeue.h"
|
||||||
#include "util/ft8message.h"
|
#include "util/ft8message.h"
|
||||||
@ -26,11 +27,13 @@
|
|||||||
#include "ft8demodsettings.h"
|
#include "ft8demodsettings.h"
|
||||||
#include "ft8demodworker.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_packing(packing),
|
||||||
m_periodTS(periodTS)
|
m_periodTS(periodTS),
|
||||||
|
m_baseFrequency(baseFrequency)
|
||||||
{
|
{
|
||||||
m_msgReportFT8Messages = MsgReportFT8Messages::create();
|
m_msgReportFT8Messages = MsgReportFT8Messages::create();
|
||||||
|
m_msgReportFT8Messages->setBaseFrequency(baseFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
int FT8DemodWorker::FT8Callback::hcb(
|
int FT8DemodWorker::FT8Callback::hcb(
|
||||||
@ -69,22 +72,20 @@ int FT8DemodWorker::FT8Callback::hcb(
|
|||||||
ft8Message.nbCorrectBits = correct_bits;
|
ft8Message.nbCorrectBits = correct_bits;
|
||||||
ft8Message.dt = off - 0.5;
|
ft8Message.dt = off - 0.5;
|
||||||
ft8Message.df = hz0;
|
ft8Message.df = hz0;
|
||||||
ft8Message.call1 = QString(call1.c_str());
|
ft8Message.call1 = QString(call1.c_str()).simplified();
|
||||||
ft8Message.call2 = QString(call2.c_str());
|
ft8Message.call2 = QString(call2.c_str()).simplified();
|
||||||
ft8Message.loc = QString(loc.c_str());
|
ft8Message.loc = QString(loc.c_str()).simplified();
|
||||||
ft8Message.decoderInfo = QString(comment);
|
ft8Message.decoderInfo = QString(comment);
|
||||||
cycle_mu.unlock();
|
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,
|
pass,
|
||||||
(int)snr,
|
(int)snr,
|
||||||
correct_bits,
|
correct_bits,
|
||||||
off - 0.5,
|
off - 0.5,
|
||||||
hz0,
|
hz0,
|
||||||
msg.c_str(),
|
msg.c_str(),
|
||||||
call1.c_str(),
|
|
||||||
call2.c_str(),
|
|
||||||
loc.c_str(),
|
|
||||||
comment
|
comment
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -97,13 +98,19 @@ FT8DemodWorker::FT8DemodWorker() :
|
|||||||
m_decoderTimeBudget(0.5),
|
m_decoderTimeBudget(0.5),
|
||||||
m_lowFreq(200),
|
m_lowFreq(200),
|
||||||
m_highFreq(3000),
|
m_highFreq(3000),
|
||||||
m_reportingMessageQueue(nullptr)
|
m_invalidSequence(true),
|
||||||
|
m_baseFrequency(0),
|
||||||
|
m_reportingMessageQueue(nullptr),
|
||||||
|
m_channel(nullptr)
|
||||||
{
|
{
|
||||||
QString relPath = "sdrangel/ft8/save";
|
QString relPath = "sdrangel/ft8/save";
|
||||||
QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
|
QDir dir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation));
|
||||||
dir.mkpath(relPath);
|
dir.mkpath(relPath);
|
||||||
m_samplesPath = dir.absolutePath() + "/" + relPath;
|
m_samplesPath = dir.absolutePath() + "/" + relPath;
|
||||||
qDebug("FT8DemodWorker::FT8DemodWorker: samples path: %s", qPrintable(m_samplesPath));
|
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()
|
FT8DemodWorker::~FT8DemodWorker()
|
||||||
@ -111,8 +118,14 @@ FT8DemodWorker::~FT8DemodWorker()
|
|||||||
|
|
||||||
void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS)
|
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")),
|
qDebug("FT8DemodWorker::processBuffer: %6.3f %s %d:%f [%d:%d]",
|
||||||
m_nbDecoderThreads, m_decoderTimeBudget, m_lowFreq, m_highFreq);
|
m_baseFrequency / 1000000.0,
|
||||||
|
qPrintable(periodTS.toString("yyyy-MM-dd HH:mm:ss")),
|
||||||
|
m_nbDecoderThreads,
|
||||||
|
m_decoderTimeBudget,
|
||||||
|
m_lowFreq,
|
||||||
|
m_highFreq
|
||||||
|
);
|
||||||
|
|
||||||
if (m_invalidSequence)
|
if (m_invalidSequence)
|
||||||
{
|
{
|
||||||
@ -121,23 +134,8 @@ void FT8DemodWorker::processBuffer(int16_t *buffer, QDateTime periodTS)
|
|||||||
return;
|
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
|
int hints[2] = { 2, 0 }; // CQ
|
||||||
FT8Callback ft8Callback(periodTS, m_packing);
|
FT8Callback ft8Callback(periodTS, m_baseFrequency, m_packing);
|
||||||
m_ft8Decoder.getParams().nthreads = m_nbDecoderThreads;
|
m_ft8Decoder.getParams().nthreads = m_nbDecoderThreads;
|
||||||
std::vector<float> samples(15*FT8DemodSettings::m_ft8SampleRate);
|
std::vector<float> 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
|
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) {
|
if (m_reportingMessageQueue) {
|
||||||
m_reportingMessageQueue->push(ft8Callback.getReportMessage());
|
m_reportingMessageQueue->push(ft8Callback.getReportMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_logMessages)
|
||||||
|
{
|
||||||
|
const QList<FT8Message>& 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 {
|
} else {
|
||||||
delete ft8Callback.getReportMessage();
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
class QDateTime;
|
class QDateTime;
|
||||||
class MessageQueue;
|
class MessageQueue;
|
||||||
class MsgReportFT8Messages;
|
class MsgReportFT8Messages;
|
||||||
|
class ChannelAPI;
|
||||||
|
|
||||||
class FT8DemodWorker : public QObject
|
class FT8DemodWorker : public QObject
|
||||||
{
|
{
|
||||||
@ -43,12 +44,14 @@ public:
|
|||||||
void setHighFrequency(int highFreq) { m_highFreq = highFreq; }
|
void setHighFrequency(int highFreq) { m_highFreq = highFreq; }
|
||||||
void setReportingMessageQueue(MessageQueue *messageQueue) { m_reportingMessageQueue = messageQueue; }
|
void setReportingMessageQueue(MessageQueue *messageQueue) { m_reportingMessageQueue = messageQueue; }
|
||||||
void invalidateSequence() { m_invalidSequence = true; }
|
void invalidateSequence() { m_invalidSequence = true; }
|
||||||
|
void setBaseFrequency(qint64 baseFrequency) { m_baseFrequency = baseFrequency; }
|
||||||
|
void setChannel(ChannelAPI *channel) { m_channel = channel; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class FT8Callback : public FT8::CallbackInterface
|
class FT8Callback : public FT8::CallbackInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FT8Callback(const QDateTime& periodTS, FT8::Packing& packing);
|
FT8Callback(const QDateTime& periodTS, qint64 baseFrequency, FT8::Packing& packing);
|
||||||
virtual int hcb(
|
virtual int hcb(
|
||||||
int *a91,
|
int *a91,
|
||||||
float hz0,
|
float hz0,
|
||||||
@ -58,21 +61,20 @@ private:
|
|||||||
int pass,
|
int pass,
|
||||||
int correct_bits
|
int correct_bits
|
||||||
);
|
);
|
||||||
const std::map<std::string, bool>& getMsgMap() {
|
const std::map<std::string, bool>& getMsgMap() { return cycle_already; }
|
||||||
return cycle_already;
|
MsgReportFT8Messages *getReportMessage() { return m_msgReportFT8Messages; }
|
||||||
}
|
|
||||||
MsgReportFT8Messages *getReportMessage() {
|
|
||||||
return m_msgReportFT8Messages;
|
|
||||||
}
|
|
||||||
private:
|
private:
|
||||||
QMutex cycle_mu;
|
QMutex cycle_mu;
|
||||||
std::map<std::string, bool> cycle_already;
|
std::map<std::string, bool> cycle_already;
|
||||||
FT8::Packing& m_packing;
|
FT8::Packing& m_packing;
|
||||||
MsgReportFT8Messages *m_msgReportFT8Messages;
|
MsgReportFT8Messages *m_msgReportFT8Messages;
|
||||||
const QDateTime& m_periodTS;
|
const QDateTime& m_periodTS;
|
||||||
|
qint64 m_baseFrequency;
|
||||||
};
|
};
|
||||||
|
|
||||||
QString m_samplesPath;
|
QString m_samplesPath;
|
||||||
|
QString m_logsPath;
|
||||||
bool m_recordSamples;
|
bool m_recordSamples;
|
||||||
bool m_logMessages;
|
bool m_logMessages;
|
||||||
int m_nbDecoderThreads;
|
int m_nbDecoderThreads;
|
||||||
@ -80,9 +82,11 @@ private:
|
|||||||
int m_lowFreq;
|
int m_lowFreq;
|
||||||
int m_highFreq;
|
int m_highFreq;
|
||||||
bool m_invalidSequence;
|
bool m_invalidSequence;
|
||||||
|
qint64 m_baseFrequency;
|
||||||
FT8::FT8Decoder m_ft8Decoder;
|
FT8::FT8Decoder m_ft8Decoder;
|
||||||
FT8::Packing m_packing;
|
FT8::Packing m_packing;
|
||||||
MessageQueue *m_reportingMessageQueue;
|
MessageQueue *m_reportingMessageQueue;
|
||||||
|
ChannelAPI *m_channel;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // INCLUDE_FT8DEMODWORKER_H
|
#endif // INCLUDE_FT8DEMODWORKER_H
|
||||||
|
@ -42,6 +42,7 @@ class FT8_API MsgReportFT8Messages : public Message {
|
|||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
public:
|
public:
|
||||||
QList<FT8Message>& getFT8Messages() { return m_ft8Messages; }
|
QList<FT8Message>& getFT8Messages() { return m_ft8Messages; }
|
||||||
|
void setBaseFrequency(qint64 baseFrequency) { m_baseFrequency = baseFrequency; }
|
||||||
|
|
||||||
static MsgReportFT8Messages* create() {
|
static MsgReportFT8Messages* create() {
|
||||||
return new MsgReportFT8Messages();
|
return new MsgReportFT8Messages();
|
||||||
@ -49,9 +50,11 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QList<FT8Message> m_ft8Messages;
|
QList<FT8Message> m_ft8Messages;
|
||||||
|
qint64 m_baseFrequency;
|
||||||
|
|
||||||
MsgReportFT8Messages() :
|
MsgReportFT8Messages() :
|
||||||
Message()
|
Message(),
|
||||||
|
m_baseFrequency(0)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user