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"( + (?