diff --git a/.gitignore b/.gitignore
index 3ffc4aed5..2bd99ec81 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,8 @@ jnq*
*.txt
cmake-build-debug
cmake-build-release
+CMakeFiles
+fnd
+lib/77bit/tmp
+lib/tmp
+lib/ftrsd
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d6446faee..f160d6b82 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -359,6 +359,8 @@ endif (WIN32)
set (wsjt_FSRCS
# put module sources first in the hope that they get rebuilt before use
+ lib/types.f90
+ lib/C_interface_module.f90
lib/shmem.f90
lib/crc.f90
lib/fftw3mod.f90
@@ -370,6 +372,7 @@ set (wsjt_FSRCS
lib/jt65_mod.f90
lib/ft8_decode.f90
lib/ft4_decode.f90
+ lib/fst4_decode.f90
lib/jt9_decode.f90
lib/options.f90
lib/packjt.f90
@@ -396,6 +399,7 @@ set (wsjt_FSRCS
lib/badmsg.f90
lib/ft8/baseline.f90
lib/ft4/ft4_baseline.f90
+ lib/blanker.f90
lib/bpdecode40.f90
lib/bpdecode128_90.f90
lib/ft8/bpdecode174_91.f90
@@ -545,6 +549,7 @@ set (wsjt_FSRCS
lib/qra64a.f90
lib/refspectrum.f90
lib/savec2.f90
+ lib/sec0.f90
lib/sec_midn.f90
lib/setup65.f90
lib/sh65.f90
@@ -596,6 +601,20 @@ set (wsjt_FSRCS
lib/wqencode.f90
lib/wspr_downsample.f90
lib/zplot9.f90
+ lib/fst4/decode240_101.f90
+ lib/fst4/decode240_74.f90
+ lib/fst4/encode240_101.f90
+ lib/fst4/encode240_74.f90
+ lib/fst4/fst4sim.f90
+ lib/fst4/gen_fst4wave.f90
+ lib/fst4/genfst4.f90
+ lib/fst4/get_fst4_bitmetrics.f90
+ lib/fst4/get_fst4_bitmetrics2.f90
+ lib/fst4/ldpcsim240_101.f90
+ lib/fst4/ldpcsim240_74.f90
+ lib/fst4/osd240_101.f90
+ lib/fst4/osd240_74.f90
+ lib/fst4/get_crc24.f90
)
# temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit
@@ -1356,6 +1375,15 @@ target_link_libraries (ft4sim_mult wsjt_fort wsjt_cxx)
add_executable (record_time_signal Audio/tools/record_time_signal.cpp)
target_link_libraries (record_time_signal wsjt_cxx wsjt_qtmm wsjt_qt)
+add_executable (fst4sim lib/fst4/fst4sim.f90 wsjtx.rc)
+target_link_libraries (fst4sim wsjt_fort wsjt_cxx)
+
+add_executable (ldpcsim240_101 lib/fst4/ldpcsim240_101.f90 wsjtx.rc)
+target_link_libraries (ldpcsim240_101 wsjt_fort wsjt_cxx)
+
+add_executable (ldpcsim240_74 lib/fst4/ldpcsim240_74.f90 wsjtx.rc)
+target_link_libraries (ldpcsim240_74 wsjt_fort wsjt_cxx)
+
endif(WSJT_BUILD_UTILS)
# build the main application
@@ -1495,7 +1523,7 @@ install (TARGETS jt9 wsprd fmtave fcal fmeasure
if(WSJT_BUILD_UTILS)
install (TARGETS ft8code jt65code qra64code qra64sim jt9code jt4code
- msk144code
+ msk144code fst4sim
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
)
diff --git a/Configuration.ui b/Configuration.ui
index 16a248223..bc8e7f596 100644
--- a/Configuration.ui
+++ b/Configuration.ui
@@ -357,7 +357,7 @@
-
- Enable VHF/UHF/Microwave features
+ Enable VHF and submode features
@@ -3119,9 +3119,9 @@ Right click for insert and delete options.
+
+
-
-
diff --git a/Decoder/decodedtext.pri b/Decoder/decodedtext.pri
new file mode 100644
index 000000000..6aa33dc36
--- /dev/null
+++ b/Decoder/decodedtext.pri
@@ -0,0 +1,3 @@
+SOURCES += Decoder/decodedtext.cpp
+
+HEADERS += Decoder/decodedtext.h
diff --git a/Detector/Detector.pri b/Detector/Detector.pri
new file mode 100644
index 000000000..a98051194
--- /dev/null
+++ b/Detector/Detector.pri
@@ -0,0 +1,3 @@
+SOURCES += Detector/Detector.cpp
+
+HEADERS += Detector/Detector.hpp
diff --git a/Modulator/Modulator.cpp b/Modulator/Modulator.cpp
index e527ce3e1..52319eb2a 100644
--- a/Modulator/Modulator.cpp
+++ b/Modulator/Modulator.cpp
@@ -45,11 +45,12 @@ Modulator::Modulator (unsigned frameRate, double periodLengthInSeconds,
{
}
-void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
+void Modulator::start (QString mode, unsigned symbolsLength, double framesPerSymbol,
double frequency, double toneSpacing,
SoundOutput * stream, Channel channel,
bool synchronize, bool fastMode, double dBSNR, double TRperiod)
{
+ // qDebug () << "mode:" << mode << "symbolsLength:" << symbolsLength << "framesPerSymbol:" << framesPerSymbol << "frequency:" << frequency << "toneSpacing:" << toneSpacing << "channel:" << channel << "synchronize:" << synchronize << "fastMode:" << fastMode << "dBSNR:" << dBSNR << "TRperiod:" << TRperiod;
Q_ASSERT (stream);
// Time according to this computer which becomes our base time
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
@@ -69,8 +70,8 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
m_bFastMode=fastMode;
m_TRperiod=TRperiod;
unsigned delay_ms=1000;
- if(m_nsps==1920) delay_ms=500; //FT8
- if(m_nsps==576) delay_ms=300; //FT4
+ if(mode=="FT8" or (mode=="FST4" and m_nsps==720)) delay_ms=500; //FT8, FST4-15
+ if(mode=="FT4") delay_ms=300; //FT4
// noise generator parameters
if (m_addNoise) {
@@ -79,26 +80,30 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
if (m_snr > 1.0) m_fac = 3000.0 / m_snr;
}
-// round up to an exact portion of a second that allows for startup delays
- m_ic = (mstr / delay_ms) * m_frameRate * delay_ms / 1000;
-
- if(m_bFastMode) m_ic=0;
-
m_silentFrames = 0;
-// calculate number of silent frames to send, so that audio will start at
-// the nominal time "delay_ms" into the Tx sequence.
- if (synchronize && !m_tuning && !m_bFastMode) {
- m_silentFrames = m_ic + m_frameRate / (1000 / delay_ms) - (mstr * (m_frameRate / 1000));
- }
-
-// qDebug() << "aa" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.zzz")
-// << m_ic << m_silentFrames << m_silentFrames/48000.0
-// << mstr << fmod(double(ms0),1000.0*m_period);
-
+ m_ic=0;
+ if (!m_tuning && !m_bFastMode)
+ {
+ // calculate number of silent frames to send, so that audio will
+ // start at the nominal time "delay_ms" into the Tx sequence.
+ if (synchronize)
+ {
+ if(delay_ms > mstr) m_silentFrames = (delay_ms - mstr) * m_frameRate / 1000;
+ }
+
+ // adjust for late starts
+ if(!m_silentFrames && mstr >= delay_ms)
+ {
+ m_ic = (mstr - delay_ms) * m_frameRate / 1000;
+ }
+ }
initialize (QIODevice::ReadOnly, channel);
Q_EMIT stateChanged ((m_state = (synchronize && m_silentFrames) ?
Synchronizing : Active));
+
+ // qDebug() << "delay_ms:" << delay_ms << "mstr:" << mstr << "m_silentFrames:" << m_silentFrames << "m_ic:" << m_ic << "m_state:" << m_state;
+
m_stream = stream;
if (m_stream) m_stream->restart (this);
}
@@ -137,6 +142,8 @@ void Modulator::close ()
qint64 Modulator::readData (char * data, qint64 maxSize)
{
+ // qDebug () << "readData: maxSize:" << maxSize;
+
double toneFrequency=1500.0;
if(m_nsps==6) {
toneFrequency=1000.0;
@@ -152,21 +159,28 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
qint16 * end (samples + numFrames * (bytesPerFrame () / sizeof (qint16)));
qint64 framesGenerated (0);
-// if(m_ic==0) qDebug() << "Modulator::readData" << 0.001*(QDateTime::currentMSecsSinceEpoch() % (1000*m_TRperiod));
+// if(m_ic==0) qDebug() << "aa" << 0.001*(QDateTime::currentMSecsSinceEpoch() % qint64(1000*m_TRperiod))
+// << m_state << m_TRperiod << m_silentFrames << m_ic << foxcom_.wave[m_ic];
switch (m_state)
{
case Synchronizing:
{
- if (m_silentFrames) { // send silence up to first second
+ if (m_silentFrames) { // send silence up to end of start delay
framesGenerated = qMin (m_silentFrames, numFrames);
- for ( ; samples != end; samples = load (0, samples)) { // silence
- }
- m_silentFrames -= framesGenerated;
- return framesGenerated * bytesPerFrame ();
+ do
+ {
+ samples = load (0, samples); // silence
+ } while (--m_silentFrames && samples != end);
+ qDebug () << "played:" << framesGenerated << "silent frames";
+ if (!m_silentFrames)
+ {
+ Q_EMIT stateChanged ((m_state = Active));
+ }
}
- Q_EMIT stateChanged ((m_state = Active));
+ // qDebug() << "m_silentFrames:" << m_silentFrames << "m_ic:" << m_ic << "m_state:" << m_state;
+
m_cwLevel = false;
m_ramp = 0; // prepare for CW wave shaping
}
@@ -260,7 +274,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
qint16 sample;
- for (unsigned i = 0; i < numFrames && m_ic <= i1; ++i) {
+ while (samples != end && m_ic <= i1) {
isym=0;
if(!m_tuning and m_TRperiod!=3.0) isym=m_ic/(4.0*m_nsps); //Actual fsample=48000
if(m_bFastMode) isym=isym%m_symbolsLength;
@@ -305,12 +319,19 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
m_amp=32767.0;
sample=qRound(m_amp*foxcom_.wave[m_ic]);
}
-
+/*
+ if((m_ic<1000 or (4*m_symbolsLength*m_nsps - m_ic) < 1000) and (m_ic%10)==0) {
+ qDebug() << "cc" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.zzz") << m_ic << sample;
+ }
+*/
samples = load(postProcessSample(sample), samples);
++framesGenerated;
++m_ic;
}
+// qDebug() << "dd" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.zzz")
+// << m_ic << i1 << foxcom_.wave[m_ic] << framesGenerated;
+
if (m_amp == 0.0) { // TODO G4WJS: compare double with zero might not be wise
if (icw[0] == 0) {
// no CW ID to send
diff --git a/Modulator/Modulator.hpp b/Modulator/Modulator.hpp
index 1043be697..c25074efe 100644
--- a/Modulator/Modulator.hpp
+++ b/Modulator/Modulator.hpp
@@ -35,7 +35,7 @@ public:
void set_nsym(int n) {m_symbolsLength=n;}
void set_ms0(qint64 ms) {m_ms0=ms;}
- Q_SLOT void start (unsigned symbolsLength, double framesPerSymbol, double frequency,
+ Q_SLOT void start (QString mode, unsigned symbolsLength, double framesPerSymbol, double frequency,
double toneSpacing, SoundOutput *, Channel = Mono,
bool synchronize = true, bool fastMode = false,
double dBSNR = 99., double TRperiod=60.0);
diff --git a/Modulator/Modulator.pri b/Modulator/Modulator.pri
new file mode 100644
index 000000000..a90a55f7a
--- /dev/null
+++ b/Modulator/Modulator.pri
@@ -0,0 +1,3 @@
+SOURCES += Modulator/Modulator.cpp
+
+HEADERS += Modulator/Mpdulator.hpp
diff --git a/Network/wsprnet.cpp b/Network/wsprnet.cpp
index cdfed7683..669ab1554 100644
--- a/Network/wsprnet.cpp
+++ b/Network/wsprnet.cpp
@@ -8,6 +8,8 @@
#include
#include
+#include
+#include
#include
#include
#include
@@ -18,215 +20,314 @@
namespace
{
- char const * const wsprNetUrl = "http://wsprnet.org/post?";
- // char const * const wsprNetUrl = "http://127.0.0.1/post?";
+ char const * const wsprNetUrl = "http://wsprnet.org/post/";
+ //char const * const wsprNetUrl = "http://127.0.0.1:5000/post/";
+
+ //
+ // tested with this python REST mock of WSPRNet.org
+ //
+ /*
+# Mock WSPRNet.org RESTful API
+from flask import Flask, request, url_for
+from flask_restful import Resource, Api
+
+app = Flask(__name__)
+
+@app.route ('/post/', methods=['GET', 'POST'])
+def spot ():
+ if request.method == 'POST':
+ print (request.form)
+ return "1 spot(s) added"
+
+with app.test_request_context ():
+ print (url_for ('spot'))
+ */
+
+ // regexp to parse FST4W decodes
+ QRegularExpression fst4_re {R"(
+ (?