Merge branch 'release-2.5.0'

This commit is contained in:
Bill Somerville 2021-06-28 05:15:39 +01:00
commit 2c07d5af3e
No known key found for this signature in database
GPG Key ID: D864B06D1E81618F
42 changed files with 1365 additions and 1201 deletions

View File

@ -71,7 +71,7 @@ message (STATUS "******************************************************")
include (set_build_type) include (set_build_type)
# RC 0 or omitted is a development build, GA is a General Availability release build # RC 0 or omitted is a development build, GA is a General Availability release build
set_build_type (RC 1) set_build_type (RC 2)
set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}") set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}")
# #
@ -169,6 +169,7 @@ set (fort_qt_CXXSRCS
) )
set (wsjt_qt_CXXSRCS set (wsjt_qt_CXXSRCS
helper_functions.cpp
qt_helpers.cpp qt_helpers.cpp
widgets/MessageBox.cpp widgets/MessageBox.cpp
MetaDataRegistry.cpp MetaDataRegistry.cpp
@ -237,6 +238,7 @@ set (wsjt_qt_CXXSRCS
Network/NetworkAccessManager.cpp Network/NetworkAccessManager.cpp
widgets/LazyFillComboBox.cpp widgets/LazyFillComboBox.cpp
widgets/CheckableItemComboBox.cpp widgets/CheckableItemComboBox.cpp
widgets/BandComboBox.cpp
) )
set (wsjt_qtmm_CXXSRCS set (wsjt_qtmm_CXXSRCS

View File

@ -3,6 +3,7 @@
#include <QApplication> #include <QApplication>
#include <boost/log/core.hpp>
#include "Logger.hpp" #include "Logger.hpp"
class QObject; class QObject;
@ -12,8 +13,8 @@ class QEvent;
// We can't use the GUI after QApplication::exit() is called so // We can't use the GUI after QApplication::exit() is called so
// uncaught exceptions can get lost on Windows systems where there is // uncaught exceptions can get lost on Windows systems where there is
// no console terminal, so here we override QApplication::notify() and // no console terminal, so here we override QApplication::notify() and
// wrap the base class call with a try block to catch and display // wrap the base class call with a try block to catch and log any
// exceptions in a message box. // uncaught exceptions.
// //
class ExceptionCatchingApplication class ExceptionCatchingApplication
: public QApplication : public QApplication
@ -31,12 +32,16 @@ public:
} }
catch (std::exception const& e) catch (std::exception const& e)
{ {
LOG_FATAL (e.what ()); LOG_FATAL ("Unexpected exception caught in event loop: " << e.what ());
} }
catch (...) catch (...)
{ {
LOG_FATAL ("Unexpected fatal error"); LOG_FATAL ("Unexpected unknown exception caught in event loop");
} }
// There's nowhere to go from here as Qt will not pass exceptions
// through the event loop, so we must abort.
boost::log::core::get ()->flush ();
qFatal ("Aborting");
return false; return false;
} }
}; };

40
NEWS
View File

@ -12,6 +12,46 @@
Copyright 2001 - 2021 by Joe Taylor, K1JT. Copyright 2001 - 2021 by Joe Taylor, K1JT.
Release: WSJT-X 2.5.0-rc2
Jun 28, 2021
-------------------------
Remember that the WSJT-X 2.5.0 package includes MAP65 3.0.0. Changes
in the package since WSJT-X 2.5.0-rc1 include the following
enhancements and defect repairs:
MAP65:
- Compute polarization angle for Xpol systems and display to nearest
degree
- Compute and display the recommended Tx polarization
- Protect against Fortran bounds errors in several places
- Insert leading 0 when needed in UTC hours and minutes on waterfall
- Wideband Q65 synchronization corrected to include single-polarization
mode
- Corrected a one-symbol (0.6 s) delay in Q65 Tx audio
- Basic instruction document for building an MS Windows portaudio DLL
for MAP65 users who are unable to use WDM/KS drivers for their
multi-channel sound cards.
WSJT-X (including the decoder for Q65 used by MAP65):
- Increase maximum DT to 5.5 s when EME decoding is enabled in Q65
- Fix generation of Tx5 message when "hiscall" has suffix /P or /R.
- Improve width management of GUI's band-selection combo box
- Restore plotting of Q65 sync curve after a q3 decode
- Disable selection of "View | Message Averaging F7" for modes
other than JT4 and JT65
- Switching to Q65 mode now defaults to "Decode | Fast"
- Repair a long standing regression with message generation for
72-bit modes when using a compound callsign.
- Repair a defect in diagnostic logging that could cause crashes on
some platforms.
- Repair a defect which failed to strip leading and trailing spaces
on input of callsigns during validation.
- Hamlib updates including repair of defects with PTT handling on a
separate serial port via rigctld, delayed PTT with Elecraft K3
series rigs, and support for the Icom IC-575 rig.
- Updated CTY.DAT database
Release: WSJT-X 2.5.0-rc1 Release: WSJT-X 2.5.0-rc1
Jun 3, 2021 Jun 3, 2021
------------------------- -------------------------

View File

@ -12,6 +12,46 @@
Copyright 2001 - 2021 by Joe Taylor, K1JT. Copyright 2001 - 2021 by Joe Taylor, K1JT.
Release: WSJT-X 2.5.0-rc2
Jun 28, 2021
-------------------------
Remember that the WSJT-X 2.5.0 package includes MAP65 3.0.0. Changes
in the package since WSJT-X 2.5.0-rc1 include the following
enhancements and defect repairs:
MAP65:
- Compute polarization angle for Xpol systems and display to nearest
degree
- Compute and display the recommended Tx polarization
- Protect against Fortran bounds errors in several places
- Insert leading 0 when needed in UTC hours and minutes on waterfall
- Wideband Q65 synchronization corrected to include single-polarization
mode
- Corrected a one-symbol (0.6 s) delay in Q65 Tx audio
- Basic instruction document for building an MS Windows portaudio DLL
for MAP65 users who are unable to use WDM/KS drivers for their
multi-channel sound cards.
WSJT-X (including the decoder for Q65 used by MAP65):
- Increase maximum DT to 5.5 s when EME decoding is enabled in Q65
- Fix generation of Tx5 message when "hiscall" has suffix /P or /R.
- Improve width management of GUI's band-selection combo box
- Restore plotting of Q65 sync curve after a q3 decode
- Disable selection of "View | Message Averaging F7" for modes
other than JT4 and JT65
- Switching to Q65 mode now defaults to "Decode | Fast"
- Repair a long standing regression with message generation for
72-bit modes when using a compound callsign.
- Repair a defect in diagnostic logging that could cause crashes on
some platforms.
- Repair a defect which failed to strip leading and trailing spaces
on input of callsigns during validation.
- Hamlib updates including repair of defects with PTT handling on a
separate serial port via rigctld, delayed PTT with Elecraft K3
series rigs, and support for the Icom IC-575 rig.
- Updated CTY.DAT database
Release: WSJT-X 2.5.0-rc1 Release: WSJT-X 2.5.0-rc1
Jun 3, 2021 Jun 3, 2021
------------------------- -------------------------

View File

@ -93,7 +93,7 @@ namespace
<< boost::log::add_value ("Line", context.line) << boost::log::add_value ("Line", context.line)
<< boost::log::add_value ("File", file) << boost::log::add_value ("File", file)
<< boost::log::add_value ("Function", function) << boost::log::add_value ("Function", function)
<< msg.toStdWString (); << msg.toStdString ();
} }
else else
{ {
@ -101,7 +101,7 @@ namespace
<< boost::log::add_value ("Line", context.line) << boost::log::add_value ("Line", context.line)
<< boost::log::add_value ("File", file) << boost::log::add_value ("File", file)
<< boost::log::add_value ("Function", function) << boost::log::add_value ("Function", function)
<< context.category << ": " << msg.toStdWString (); << context.category << ": " << msg.toStdString ();
} }
} }
@ -132,7 +132,7 @@ namespace
#else #else
, keywords::file_name = , keywords::file_name =
#endif #endif
app_data.absoluteFilePath ("logs/wsjtx_syslog_%Y-%m.log").toStdString () app_data.absoluteFilePath ("logs/wsjtx_syslog_%Y-%m.log").toStdWString ()
, keywords::time_based_rotation = sinks::file::rotation_at_time_point (gregorian::greg_day (1), 0, 0, 0) , keywords::time_based_rotation = sinks::file::rotation_at_time_point (gregorian::greg_day (1), 0, 0, 0)
, keywords::open_mode = std::ios_base::out | std::ios_base::app , keywords::open_mode = std::ios_base::out | std::ios_base::app
#if BOOST_VERSION / 100 >= 1063 #if BOOST_VERSION / 100 >= 1063

1206
cty.dat

File diff suppressed because it is too large Load Diff

View File

@ -214,7 +214,7 @@ a suitable location like ~/build and change working directory to it:
Configure and build and install the library in a suitable place (I use Configure and build and install the library in a suitable place (I use
~/local as a root directory for installed packages. ~/local as a root directory for installed packages.
~/src/portaudio/configure --prefix=$(HOME)/local/portaudio/mingw64 \ ~/src/portaudio/configure --prefix=$HOME/local/portaudio/mingw64 \
--with-winapi=wmme,directx,wdmks --disable-static --enable-shared CFLAGS=-DNDEBUG --with-winapi=wmme,directx,wdmks --disable-static --enable-shared CFLAGS=-DNDEBUG
make && make install make && make install

View File

@ -0,0 +1,76 @@
Building the MS Windows portaudio DLL with ASIO Support
=======================================================
Some MAP65 users may not be able to use WDM/KS hosted audio devices
due to sharing issues with other applications, to circumvent this they
can build a version of the portaudio DLL with ASIO support. We cannot
provide a portaudio DLL with ASIO support as the Steinberg ASIO SDK
license prevents redistribution of drivers or hosting applications
without a commercial license agreement, nor is the Steinberg ASIO SDK
license compatible with the GPL v3 license that MAP65 is released
under. Users may build a portaudio DLL themselves, strictly for
personal use, under the terms of the Steinberg ASIO license.
Building portaudio on MS Windows is done most easily using the MinGW
(GNU) tool-chain which can be installed on MS Windows using the MSYS2
unix like environment which in turn includes a package manager
(pacman) that allows simple installation of necessary prerequisite
packages like the MinGW 64-bit tool-chain. To install MSYS2 download
the latest 64-bit installer from the MSYS2 project web site. This page
contains links to the installer download and detailed instructions to
install and bring up-to-date the base MSYS2 packages.
https://www.msys2.org/wiki/MSYS2-installation/
Take particular care to restart the MSYS2 shell window when directed
to.
Once MSYS2 is installed you will find a start menu entry labelled
"MSYS2 MinGW 64-bit", use that to start a fresh MSYS2 shell window for
the rest of these instructions.
The first step is to install some prerequisite packages which contain
the tools needed to prepare and build the portaudio DLL. Execute the
following command to do that:
pacman -S make diffutils unzip mingw-w64-x86_64-gcc sed tar curl
Then make directories to put downloaded sources in and for building:
mkdir -p ~/src ~/build/portaudio
Fetch and unpack the Steinberg ASIO SDK (note the ASIO SDK license
document included, particularly that it strictly disallows
redistribution of the DLL we will be building here), and portaudio
sources:
curl -Lo ~/src/asiosdk.zip https://www.steinberg.net/asiosdk
(cd ~/src ; unzip asiosdk.zip)
curl -O --output-dir ~/src \
http://files.portaudio.com/archives/pa_stable_v190700_20210406.tgz
tar -C ~/src -xf ~/src/pa_stable_v190700_20210406.tgz
Patch and build the portaudio library:
sed -i -e 's/-luuid//g' ~/src/portaudio/configure
cd ~/build/portaudio
~/src/portaudio/configure --with-winapi=wmme,directx,wdmks,asio \
--with-asiodir=$HOME/src/asiosdk_2.3.3_2019-06-14 \
--disable-static --enable-shared
make -j
You can check the library build is working by running a test program
that was also built:
bin/pa_devs
which should list every audio device on your system by every host API,
if all is well that should include the audio devices on your system
with ASIO drivers.
Copy the new portaudio DLL to your WSJT-X/MAP65 installation directory:
cp lib/.libs/libportaudio-2.dll /c/WSJT/wsjtx/bin/
Note that if you upgrade WSJT-X you will need to copy this DLL again
since it will be overwritten by one with no ASIO support.

View File

@ -141,7 +141,7 @@ C:\Tools\boost-build\MinGW32\bin\b2 -j8 toolset=gcc ^
--build-dir=%USERPROFILE%\build\boost ^ --build-dir=%USERPROFILE%\build\boost ^
address-model=32 architecture=x86 variant=debug,release ^ address-model=32 architecture=x86 variant=debug,release ^
link=shared threading=multi ^ link=shared threading=multi ^
--with-log --with-stacktrace --prefix=C:\Tools\boost install --with-log --with-stacktrace --with-timer --prefix=C:\Tools\boost install
If all is well you should see the following line about a 1/3 of the If all is well you should see the following line about a 1/3 of the
way through the initial configuration steps. way through the initial configuration steps.
@ -188,7 +188,7 @@ cd ..\..
C:\Tools\boost-build\MinGW64\bin\b2 -j8 toolset=gcc-8~64 ^ C:\Tools\boost-build\MinGW64\bin\b2 -j8 toolset=gcc-8~64 ^
address-model=64 architecture=x86 variant=debug,release ^ address-model=64 architecture=x86 variant=debug,release ^
link=shared threading=multi ^ link=shared threading=multi ^
--with-log --with-stacktrace ^ --with-log --with-stacktrace --with-timer ^
--build-dir=%USERPROFILE%\build\boost ^ --build-dir=%USERPROFILE%\build\boost ^
--prefix=C:\Tools\boost install --prefix=C:\Tools\boost install
@ -206,9 +206,11 @@ After some time it should complete with something like:
warnings can usually be ignored. If successful; you can release some warnings can usually be ignored. If successful; you can release some
space by cleaning the build tree: space by cleaning the build tree:
C:\Tools\boost-build\MinGW32\bin\b2 toolset=gcc-8~64 ^ C:\Tools\boost-build\MinGW64\bin\b2 toolset=gcc-8~64 ^
address-model=64 --build-dir=%USERPROFILE%\build\boost ^ address-model=64 --build-dir=%USERPROFILE%\build\boost ^
--build-type=complete clean --build-type=complete clean
Run-time Environment Run-time Environment
-------------------- --------------------

View File

@ -1,9 +1,9 @@
#include "getfile.h" #include "getfile.h"
#include <QDir>
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
#include <QRandomGenerator> #include <QRandomGenerator>
#include <random> #include <random>
#endif #endif
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -22,155 +22,6 @@
#include <err.h> #include <err.h>
#endif #endif
#include "commons.h"
extern dec_data dec_data;
void getfile(QString fname, int ntrperiod)
{
// struct WAVHDR {
// char ariff[4];
// int lenfile;
// char awave[4];
// char afmt[4];
// int lenfmt;
// short nfmt2;
// short nchan2;
// int nsamrate;
// int nbytesec;
// short nbytesam2;
// short nbitsam2;
// char adata[4];
// int ndata;
// } hdr;
char name[512];
strncpy(name,fname.toLatin1(), sizeof (name) - 1);
name[sizeof (name) - 1] = '\0';
FILE* fp=fopen(name,"rb");
int i1=fname.lastIndexOf("/");
QString baseName=fname.mid(i1+1);
i1=fname.indexOf(".wav",0,Qt::CaseInsensitive);
dec_data.params.nutc=0;
if(i1>0) {
int i0=fname.indexOf("_",-11);
if(i1==i0+7) {
dec_data.params.nutc=fname.mid(i1-6,6).toInt();
} else {
dec_data.params.nutc=100*fname.mid(i1-4,4).toInt();
}
}
if(ntrperiod > 120 or ntrperiod <0) ntrperiod=120;
int npts=ntrperiod*12000;
memset(dec_data.d2,0,2*npts);
if(fp != NULL) {
struct
{
char id[4];
uint32_t size;
} desc;
char type[4];
struct
{
uint16_t nfmt2;
uint16_t nchan2;
uint32_t nsamrate;
uint32_t nbytesec;
uint16_t nbytesam2;
uint16_t nbitsam2;
} fmt;
// read header
if (fread(&desc, sizeof desc, 1, fp) < 1) return; // RIFF
if (fread(type, sizeof type, 1, fp) < 1) return; // WAVE
do
{
if (fread(&desc, sizeof desc, 1, fp) < 1) return; // WAVE component
if (!memcmp(desc.id,"fmt ",4)) {
fpos_t pos;
fgetpos(fp,&pos);
if (fread(&fmt,sizeof fmt,1,fp) < 1) return;
fsetpos(fp,&pos);
}
if (!memcmp(desc.id,"data",sizeof desc.id)) break;
} while (!fseek(fp,(desc.size + 1) / 2 * 2,SEEK_CUR));
// Read (and ignore) a 44-byte WAV header; then read data
// int n=fread(&hdr,1,44,fp);
int n=fread(dec_data.d2,2,npts,fp);
if(fmt.nsamrate==11025) wav12_(dec_data.d2,dec_data.d2,&n,(short*)&fmt.nbitsam2);
fclose(fp);
dec_data.params.newdat=1;
dec_data.params.kin=n;
}
}
void savewav(QString fname, int ntrperiod)
{
struct {
char ariff[4]; //ChunkID: "RIFF"
int nchunk; //ChunkSize: 36+SubChunk2Size
char awave[4]; //Format: "WAVE"
char afmt[4]; //Subchunk1ID: "fmt "
int lenfmt; //Subchunk1Size: 16
short int nfmt2; //AudioFormat: 1
short int nchan2; //NumChannels: 1
int nsamrate; //SampleRate: 12000
int nbytesec; //ByteRate: SampleRate*NumChannels*BitsPerSample/8
short int nbytesam2; //BlockAlign: NumChannels*BitsPerSample/8
short int nbitsam2; //BitsPerSample: 16
char adata[4]; //Subchunk2ID: "data"
int ndata; //Subchunk2Size: numSamples*NumChannels*BitsPerSample/8
} hdr;
int npts=ntrperiod*12000;
// qint16* buf=(qint16*)malloc(2*npts);
char name[512];
strncpy(name,fname.toLatin1(),sizeof (name) - 1);
name[sizeof (name) - 1] = '\0';
FILE* fp=fopen(name,"wb");
if(fp != NULL) {
// Write a WAV header
hdr.ariff[0]='R';
hdr.ariff[1]='I';
hdr.ariff[2]='F';
hdr.ariff[3]='F';
hdr.nchunk=36 + 2*npts;
hdr.awave[0]='W';
hdr.awave[1]='A';
hdr.awave[2]='V';
hdr.awave[3]='E';
hdr.afmt[0]='f';
hdr.afmt[1]='m';
hdr.afmt[2]='t';
hdr.afmt[3]=' ';
hdr.lenfmt=16;
hdr.nfmt2=1;
hdr.nchan2=1;
hdr.nsamrate=12000;
hdr.nbytesec=2*12000;
hdr.nbytesam2=2;
hdr.nbitsam2=16;
hdr.adata[0]='d';
hdr.adata[1]='a';
hdr.adata[2]='t';
hdr.adata[3]='a';
hdr.ndata=2*npts;
fwrite(&hdr,sizeof(hdr),1,fp);
// memcpy(dec_data.d2,buf,2*npts);
// fwrite(buf,2,npts,fp);
fwrite(dec_data.d2,2,npts,fp);
fclose(fp);
}
// free(buf);
}
//#define MAX_RANDOM 0x7fffffff //#define MAX_RANDOM 0x7fffffff
/* Generate gaussian random float with mean=0 and std_dev=1 */ /* Generate gaussian random float with mean=0 and std_dev=1 */
float gran() float gran()
@ -202,72 +53,3 @@ float gran()
return v2*fac; return v2*fac;
#endif #endif
} }
int ptt(int nport, int ntx, int* iptt, int* nopen)
{
#ifdef WIN32
static HANDLE hFile;
char s[10];
int i3=1,i4=1,i5=1,i6=1,i9=1,i00=1; //Defs to silence compiler warning
if(nport==0) {
*iptt=ntx;
return 0;
}
if(ntx && (!(*nopen))) {
sprintf(s,"\\\\.\\COM%d",nport);
hFile=CreateFile(TEXT(s),GENERIC_WRITE,0,NULL,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile==INVALID_HANDLE_VALUE) {
QString t;
t = t.asprintf("Cannot open COM port %d for PTT\n",nport);
return 1;
}
*nopen=1;
}
if(ntx && *nopen) {
i3=EscapeCommFunction(hFile,SETRTS);
i5=EscapeCommFunction(hFile,SETDTR);
*iptt=1;
}
else {
i4=EscapeCommFunction(hFile,CLRRTS);
i6=EscapeCommFunction(hFile,CLRDTR);
i9=EscapeCommFunction(hFile,CLRBREAK);
i00=CloseHandle(hFile);
*iptt=0;
*nopen=0;
}
if((i3+i4+i5+i6+i9+i00)==-999) return 1; //Silence compiler warning
return 0;
#else
int control=TIOCM_RTS | TIOCM_DTR;
// int control = TIOCM_RTS;
static int fd;
if(*nopen==0) {
fd=open("/dev/ttyUSB0",O_RDWR | O_NONBLOCK);
if(fd<0) {
return -1;
}
*nopen=1;
}
if(ntx) {
ioctl(fd, TIOCMBIS, &control);
*iptt=1;
*nopen=1;
} else {
ioctl(fd, TIOCMBIC, &control);
close(fd);
*iptt=0;
*nopen=0;
}
return 0;
#endif
if((nport+ntx+(*iptt)==-99999)) *nopen=0; //Silence compiler warning
return 0;
}

View File

@ -1,19 +1,8 @@
// -*- Mode: C++ -*- // -*- Mode: C++ -*-
#ifndef GETFILE_H #ifndef GETFILE_H
#define GETFILE_H #define GETFILE_H
#include <QString>
#include <QFile>
#include <QDebug> #include <QDebug>
void getfile(QString fname, int ntrperiod);
float gran(); float gran();
//int ptt(int* nport, int* ntx, int* iptt);
int ptt(int nport, int ntx, int* iptt, int* nopen);
extern "C" {
int ptt_(int nport, int ntx, int* iptt, int* nopen);
void wav12_(short d2[], short d1[], int* nbytes, short* nbitsam2);
}
#endif // GETFILE_H #endif // GETFILE_H

33
helper_functions.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "helper_functions.h"
double tx_duration(QString mode, double trPeriod, int nsps, bool bFast9)
{
double txt=0.0;
if(mode=="FT4") txt=1.0 + 105*576/12000.0; // FT4
if(mode=="FT8") txt=1.0 + 79*1920/12000.0; // FT8
if(mode=="JT4") txt=1.0 + 207.0*2520/11025.0; // JT4
if(mode=="JT9") txt=1.0 + 85.0*nsps/12000.0; // JT9
if(mode=="JT65") txt=1.0 + 126*4096/11025.0; // JT65
if(mode=="Q65") { // Q65
if(trPeriod==15) txt=0.5 + 85*1800/12000.0;
if(trPeriod==30) txt=0.5 + 85*3600/12000.0;
if(trPeriod==60) txt=1.0 + 85*7200/12000.0;
if(trPeriod==120) txt=1.0 + 85*16000/12000.0;
if(trPeriod==300) txt=1.0 + 85*41472/12000.0;
}
if(mode=="WSPR") txt=2.0 + 162*8192/12000.0; // WSPR
if(mode=="FST4" or mode=="FST4W") { //FST4, FST4W
if(trPeriod==15) txt=1.0 + 160*720/12000.0;
if(trPeriod==30) txt=1.0 + 160*1680/12000.0;
if(trPeriod==60) txt=1.0 + 160*3888/12000.0;
if(trPeriod==120) txt=1.0 + 160*8200/12000.0;
if(trPeriod==300) txt=1.0 + 160*21504/12000.0;
if(trPeriod==900) txt=1.0 + 160*66560/12000.0;
if(trPeriod==1800) txt=1.0 + 160*134400/12000.0;
}
if(mode=="MSK144" or bFast9) {
txt=trPeriod-0.25; // JT9-fast, MSK144
}
if(mode=="Echo") txt=2.4;
return txt;
}

7
helper_functions.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef HELPER_FUNCTIONS_H
#define HELPER_FUNCTIONS_H
#include <QString>
double tx_duration(QString mode, double trPeriod, int nsps, bool bFast9);
#endif // HELPER_FUNCTIONS_H

View File

@ -148,13 +148,16 @@ contains
nused=1 nused=1
iavg=0 iavg=0
call timer('q65_dec0',0) call timer('q65_dec0',0)
! Call top-level routine in q65 module: establish sync and try for a q3 decode. ! Call top-level routine in q65 module: establish sync and try for a
! q3 or q0 decode.
call q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, & call q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
emedelay,xdt,f0,snr1,width,dat4,snr2,idec) emedelay,xdt,f0,snr1,width,dat4,snr2,idec)
call timer('q65_dec0',1) call timer('q65_dec0',1)
! write(*,3001) '=a',sum(abs(float(iwave))),nfqso,ntol,ndepth,xdt,f0,idec
!3001 format(a2,f15.0,3i5,f7.2,f7.1,i5)
if(idec.ge.0) then if(idec.ge.0) then
dtdec=xdt !We have a list-decode result at nfqso dtdec=xdt !We have a q3 or q0 decode at nfqso
f0dec=f0 f0dec=f0
go to 100 go to 100
endif endif
@ -207,6 +210,7 @@ contains
call q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, & call q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
emedelay,xdt,f0,snr1,width,dat4,snr2,idec) emedelay,xdt,f0,snr1,width,dat4,snr2,idec)
call timer('list_avg',1) call timer('list_avg',1)
if(idec.ge.0) then if(idec.ge.0) then
dtdec=xdt !We have a list-decode result from averaged data dtdec=xdt !We have a list-decode result from averaged data
f0dec=f0 f0dec=f0

View File

@ -124,7 +124,7 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
dtstep=nsps/(NSTEP*12000.0) !Step size in seconds dtstep=nsps/(NSTEP*12000.0) !Step size in seconds
lag1=-1.0/dtstep lag1=-1.0/dtstep
lag2=1.0/dtstep + 0.9999 lag2=1.0/dtstep + 0.9999
if(nsps.ge.3600 .and. emedelay.gt.0) lag2=4.0/dtstep + 0.9999 !Include EME if(nsps.ge.3600 .and. emedelay.gt.0) lag2=5.5/dtstep + 0.9999 !Include EME
j0=0.5/dtstep j0=0.5/dtstep
if(nsps.ge.7200) j0=1.0/dtstep !Nominal start-signal index if(nsps.ge.7200) j0=1.0/dtstep !Nominal start-signal index
@ -139,16 +139,17 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
endif endif
i0=nint(nfqso/df) !Target QSO frequency i0=nint(nfqso/df) !Target QSO frequency
if(i0-64.lt.1 .or. i0-65+LL.gt.iz) go to 900 !Frequency out of range ii1=max(1,i0-64)
call pctile(s1(i0-64:i0-65+LL,1:jz),LL*jz,45,base) ii2=i0-65+LL
call pctile(s1(ii1:ii2,1:jz),ii2-ii1+1*jz,45,base)
s1=s1/base s1=s1/base
s1raw=s1 s1raw=s1
! Apply fast AGC to the symbol spectra ! Apply fast AGC to the symbol spectra
s1max=20.0 !Empirical choice s1max=20.0 !Empirical choice
do j=1,jz !### Maybe wrong way? ### do j=1,jz !### Maybe wrong way? ###
smax=maxval(s1(i0-64:i0-65+LL,j)) smax=maxval(s1(ii1:ii2,j))
if(smax.gt.s1max) s1(i0-64:i0-65+LL,j)=s1(i0-64:i0-65+LL,j)*s1max/smax if(smax.gt.s1max) s1(ii1:ii2,j)=s1(ii1:ii2,j)*s1max/smax
enddo enddo
dat4=0 dat4=0
@ -162,9 +163,10 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
call timer('list_dec',0) call timer('list_dec',0)
call q65_dec_q3(s1,iz,jz,s3,LL,ipk,jpk,snr2,dat4,idec,decoded) call q65_dec_q3(s1,iz,jz,s3,LL,ipk,jpk,snr2,dat4,idec,decoded)
call timer('list_dec',1) call timer('list_dec',1)
if(idec.eq.3) go to 900 !Good q3 decode, we're done ! If idec=3 we have a q3 decode. Continue to compute sync curve for plotting.
endif endif
! Get 2d CCF and ccf2 using sync symbols only
if(iavg.eq.0) then if(iavg.eq.0) then
call timer('ccf_22a ',0) call timer('ccf_22a ',0)
call q65_ccf_22(s1,iz,jz,nfqso,ntol,ndepth,ntrperiod,iavg,ipk,jpk, & call q65_ccf_22(s1,iz,jz,nfqso,ntol,ndepth,ntrperiod,iavg,ipk,jpk, &
@ -172,7 +174,7 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
call timer('ccf_22a ',1) call timer('ccf_22a ',1)
endif endif
! Get 2d CCF and ccf2 using sync symbols only ! Get 2d CCF and ccf2_avg using sync symbols only
if(iavg.ge.1) then if(iavg.ge.1) then
call timer('ccf_22b ',0) call timer('ccf_22b ',0)
call q65_ccf_22(s1,iz,jz,nfqso,ntol,ndepth,ntrperiod,iavg,ipk,jpk, & call q65_ccf_22(s1,iz,jz,nfqso,ntol,ndepth,ntrperiod,iavg,ipk,jpk, &
@ -211,7 +213,7 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
call q65_write_red(iz,xdt,ccf2_avg,ccf2) call q65_write_red(iz,xdt,ccf2_avg,ccf2)
if(iavg.eq.0 .or. iavg.eq.2) then if(idec.lt.0 .and. (iavg.eq.0 .or. iavg.eq.2)) then
call q65_dec_q012(s3,LL,snr2,dat4,idec,decoded) call q65_dec_q012(s3,LL,snr2,dat4,idec,decoded)
endif endif
@ -439,8 +441,8 @@ subroutine q65_ccf_22(s1,iz,jz,nfqso,ntol,ndepth,ntrperiod,iavg,ipk,jpk, &
ib=min(nfb,4900)/df ib=min(nfb,4900)/df
if(nqd.ne.1 .or. iavg.ne.0) max_drift=0 if(nqd.ne.1 .or. iavg.ne.0) max_drift=0
if(max_drift.ne.0) then if(max_drift.ne.0) then
ia=nint((nfqso-ntol)/df) ia=max(nint(100/df),nint((nfqso-ntol)/df))
ib=nint((nfqso+ntol)/df) ib=min(nint(4900/df),nint((nfqso+ntol)/df))
endif endif
do i=ia,ib do i=ia,ib

View File

@ -73,7 +73,7 @@ program test_q65
! 1 2 3 4 5 6 7 ! 1 2 3 4 5 6 7
! 1234567890123456789012345678901234567890123456789012345678901234567890123456' ! 1234567890123456789012345678901234567890123456789012345678901234567890123456'
cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 0.0 1 60 100 -10.0 > junk0' cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 0.0 1 60 100 -10.0 > junk0'
cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A -Q 3 -f 1500 *.wav > junk' cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A -Q 3 -f 1500 -X 32 *.wav > junk'
write(cmd1(10:33),'(a)') '"'//msg//'"' write(cmd1(10:33),'(a)') '"'//msg//'"'
cmd1(35:35)=csubmode cmd1(35:35)=csubmode

View File

@ -60,8 +60,8 @@ set (libm65_FSRCS
nchar.f90 nchar.f90
noisegen.f90 noisegen.f90
packjt.f90 packjt.f90
# pctile.f90
pfxdump.f90 pfxdump.f90
polfit.f90
recvpkt.f90 recvpkt.f90
rfile3a.f90 rfile3a.f90
s3avg.f90 s3avg.f90
@ -80,6 +80,7 @@ set (libm65_FSRCS
trimlist.f90 trimlist.f90
twkfreq.f90 twkfreq.f90
twkfreq_xy.f90 twkfreq_xy.f90
txpol.f90
wavhdr.f90 wavhdr.f90
f77_wisdom.f f77_wisdom.f

View File

@ -36,7 +36,7 @@ subroutine gen_q65_wave(msg,ntxfreq,mode65,msgsent,iwave,nwave)
j0=0 j0=0
do i=1,iz do i=1,iz
t=t+dt t=t+dt
j=t/tsym j=t/tsym + 1.0
if(j.ne.j0) then if(j.ne.j0) then
f=f0 + itone(j)*dfgen f=f0 + itone(j)*dfgen
dphi=twopi*dt*f dphi=twopi*dt*f

View File

@ -19,7 +19,7 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
real*8 fcenter real*8 fcenter
character*22 msg(MAXMSG) character*22 msg(MAXMSG)
character*3 shmsg0(4) character*3 shmsg0(4)
character mycall*12,hiscall*12,mygrid*6,hisgrid*6,grid*6,cp*1,cm*1 character mycall*12,hiscall*12,mygrid*6,hisgrid*6,cp*1,cm*1
integer indx(MAXMSG),nsiz(MAXMSG) integer indx(MAXMSG),nsiz(MAXMSG)
logical done(MAXMSG) logical done(MAXMSG)
logical xpol,bq65,q65b_called logical xpol,bq65,q65b_called
@ -43,12 +43,13 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
mode65=mod(nmode,10) mode65=mod(nmode,10)
if(mode65.eq.3) mode65=4 if(mode65.eq.3) mode65=4
mode_q65=nmode/10 mode_q65=nmode/10
xpol=(nxpol.ne.0)
nts_jt65=2**(mode65-1) !JT65 tone separation factor nts_jt65=2**(mode65-1) !JT65 tone separation factor
nts_q65=2**(mode_q65) !Q65 tone separation factor nts_q65=2**(mode_q65) !Q65 tone separation factor
if(nagain.eq.0) then if(nagain.eq.0) then
call timer('get_cand',0) call timer('get_cand',0)
call get_candidates(ss,savg,mfa,mfb,nts_jt65,nts_q65,cand,ncand) call get_candidates(ss,savg,xpol,mfa,mfb,nts_jt65,nts_q65,cand,ncand)
call timer('get_cand',1) call timer('get_cand',1)
candec=.false. candec=.false.
endif endif
@ -66,7 +67,6 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
mcall3a=mcall3b mcall3a=mcall3b
mousefqso0=mousefqso mousefqso0=mousefqso
xpol=(nxpol.ne.0)
if(.not.xpol) ndphi=0 if(.not.xpol) ndphi=0
nsum=0 nsum=0
@ -318,28 +318,7 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
if(npol.lt.0) npol=npol+180 if(npol.lt.0) npol=npol+180
endif endif
! If Tx station's grid is in decoded message, compute optimum TxPol call txpol(xpol,decoded,mygrid,npol,nxant,ntxpol,cp)
i1=index(decoded,' ')
i2=index(decoded(i1+1:),' ') + i1
grid=' '
if(i2.ge.8 .and. i2.le.18) grid=decoded(i2+1:i2+4)//'mm'
ntxpol=0
cp=' '
if(xpol) then
if(grid(1:1).ge.'A' .and. grid(1:1).le.'R' .and. &
grid(2:2).ge.'A' .and. grid(2:2).le.'R' .and. &
grid(3:3).ge.'0' .and. grid(3:3).le.'9' .and. &
grid(4:4).ge.'0' .and. grid(4:4).le.'9') then
ntxpol=mod(npol-nint(2.0*dpol(mygrid,grid))+720,180)
if(nxant.eq.0) then
cp='H'
if(ntxpol.gt.45 .and. ntxpol.le.135) cp='V'
else
cp='/'
if(ntxpol.ge.90 .and. ntxpol.lt.180) cp='\'
endif
endif
endif
if(ndphi.eq.0) then if(ndphi.eq.0) then
write(*,1010) nkHz,ndf,npol,nutc,dt,nsync2, & write(*,1010) nkHz,ndf,npol,nutc,dt,nsync2, &
@ -368,9 +347,9 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
q65b_called=.true. q65b_called=.true.
f0=cand(icand)%f f0=cand(icand)%f
call timer('q65b ',0) call timer('q65b ',0)
call q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol, & call q65b(nutc,nqd,nxant,fcenter,nfcal,nfsample,ikhz,mousedf, &
xpol,mycall,hiscall,hisgrid,mode_q65,f0,fqso,newdat, & ntol,xpol,mycall,mygrid, hiscall,hisgrid,mode_q65,f0,fqso, &
nagain,max_drift,idec) newdat,nagain,max_drift,idec)
call timer('q65b ',1) call timer('q65b ',1)
if(idec.ge.0) candec(icand)=.true. if(idec.ge.0) candec(icand)=.true.
enddo enddo
@ -379,9 +358,9 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
ikhz=mousefqso ikhz=mousefqso
f0=freq - (nkhz_center-48.0-1.27046) !### ??? ### f0=freq - (nkhz_center-48.0-1.27046) !### ??? ###
call timer('q65b ',0) call timer('q65b ',0)
call q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol, & call q65b(nutc,nqd,nxant,fcenter,nfcal,nfsample,ikhz,mousedf, &
xpol,mycall,hiscall,hisgrid,mode_q65,f0,fqso,newdat, & ntol,xpol,mycall,mygrid,hiscall,hisgrid,mode_q65,f0,fqso, &
nagain,max_drift,idec) newdat,nagain,max_drift,idec)
call timer('q65b ',1) call timer('q65b ',1)
endif endif
endif endif
@ -416,8 +395,8 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
ikhz=nint(freq) ikhz=nint(freq)
f0=cand(icand)%f f0=cand(icand)%f
call timer('q65b ',0) call timer('q65b ',0)
call q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol, & call q65b(nutc,nqd,nxant,fcenter,nfcal,nfsample,ikhz,mousedf,ntol, &
xpol,mycall,hiscall,hisgrid,mode_q65,f0,fqso,newdat, & xpol,mycall,mygrid,hiscall,hisgrid,mode_q65,f0,fqso,newdat, &
nagain,max_drift,idec) nagain,max_drift,idec)
call timer('q65b ',1) call timer('q65b ',1)
if(idec.ge.0) candec(icand)=.true. if(idec.ge.0) candec(icand)=.true.
@ -494,28 +473,8 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
if(npol.lt.0) npol=npol+180 if(npol.lt.0) npol=npol+180
endif endif
! If Tx station's grid is in decoded message, compute optimum TxPol call txpol(xpol,decoded,mygrid,npol,nxant,ntxpol,cp)
i1=index(decoded,' ')
i2=index(decoded(i1+1:),' ') + i1
grid=' '
if(i2.ge.8 .and. i2.le.18) grid=decoded(i2+1:i2+4)//'mm'
ntxpol=0
cp=' '
if(xpol) then
if(grid(1:1).ge.'A' .and. grid(1:1).le.'R' .and. &
grid(2:2).ge.'A' .and. grid(2:2).le.'R' .and. &
grid(3:3).ge.'0' .and. grid(3:3).le.'9' .and. &
grid(4:4).ge.'0' .and. grid(4:4).le.'9') then
ntxpol=mod(npol-nint(2.0*dpol(mygrid,grid))+720,180)
if(nxant.eq.0) then
cp='H'
if(ntxpol.gt.45 .and. ntxpol.le.135) cp='V'
else
cp='/'
if(ntxpol.ge.90 .and. ntxpol.lt.180) cp='\'
endif
endif
endif
cmode='#A' cmode='#A'
if(mode65.eq.2) cmode='#B' if(mode65.eq.2) cmode='#B'
if(mode65.eq.4) cmode='#C' if(mode65.eq.4) cmode='#C'

86
map65/libm65/polfit.f90 Normal file
View File

@ -0,0 +1,86 @@
subroutine polfit(y,npts,a)
! Input: y(npts) !Expect npts=4
! Output: a(1) = baseline
! a(2) = amplitude
! a(3) = theta (deg)
real y(npts)
real a(3)
real deltaa(3)
integer ipk(1)
save
! Set starting values:
a(1)=minval(y)
a(2)=maxval(y)-a(1)
ipk=maxloc(y)
a(3)=(ipk(1)-1)*45.0
deltaa(1:2)=0.1*(a(2)-a(1))
deltaa(3)=10.0
nterms=3
! Start the iteration
chisqr=0.
chisqr0=1.e6
iters=10
do iter=1,iters
do j=1,nterms
chisq1=fchisq_pol(y,npts,a)
fn=0.
delta=deltaa(j)
10 a(j)=a(j)+delta
chisq2=fchisq_pol(y,npts,a)
if(chisq2.eq.chisq1) go to 10
if(chisq2.gt.chisq1) then
delta=-delta !Reverse direction
a(j)=a(j)+delta
tmp=chisq1
chisq1=chisq2
chisq2=tmp
endif
20 fn=fn+1.0
a(j)=a(j)+delta
chisq3=fchisq_pol(y,npts,a)
if(chisq3.lt.chisq2) then
chisq1=chisq2
chisq2=chisq3
go to 20
endif
! Find minimum of parabola defined by last three points
delta=delta*(1./(1.+(chisq1-chisq2)/(chisq3-chisq2))+0.5)
a(j)=a(j)-delta
deltaa(j)=deltaa(j)*fn/3.
! write(*,4000) iter,j,a,deltaa,chisq2
!4000 format(2i2,2(2x,3f8.2),f12.5)
enddo
chisqr=fchisq_pol(y,npts,a)
! write(*,4000) 0,0,a,chisqr
if(deltaa(1).lt.0.01*(a(2)-a(1)) .and. deltaa(2).lt.0.01*(a(2)-a(1)) &
.and. deltaa(3).lt.1.0) exit
if(chisqr/chisqr0.gt.0.99) exit
a(3)=mod(a(3)+360.0,180.0)
chisqr0=chisqr
enddo
return
end subroutine polfit
real function fchisq_pol(y,npts,a)
real y(npts),a(3)
data rad/57.2957795/
chisq = 0.
do i=1,npts
theta=(i-1)*45.0
yfit=a(1) + a(2)*cos((theta-a(3))/rad)**2
chisq=chisq + (y(i) - yfit)**2
enddo
fchisq_pol=chisq
return
end function fchisq_pol

View File

@ -1,5 +1,6 @@
subroutine q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, & subroutine q65b(nutc,nqd,nxant,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, &
mycall0,hiscall0,hisgrid,mode_q65,f0,fqso,newdat,nagain,max_drift,idec) mycall0,mygrid,hiscall0,hisgrid,mode_q65,f0,fqso,newdat,nagain, &
max_drift,idec)
! This routine provides an interface between MAP65 and the Q65 decoder ! This routine provides an interface between MAP65 and the Q65 decoder
! in WSJT-X. All arguments are input data obtained from the MAP65 GUI. ! in WSJT-X. All arguments are input data obtained from the MAP65 GUI.
@ -16,6 +17,7 @@ subroutine q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, &
parameter (MAXFFT1=5376000) !56*96000 parameter (MAXFFT1=5376000) !56*96000
parameter (MAXFFT2=336000) !56*6000 (downsampled by 1/16) parameter (MAXFFT2=336000) !56*6000 (downsampled by 1/16)
parameter (NMAX=60*12000) parameter (NMAX=60*12000)
parameter (RAD=57.2957795)
! type(hdr) h !Header for the .wav file ! type(hdr) h !Header for the .wav file
integer*2 iwave(60*12000) integer*2 iwave(60*12000)
complex ca(MAXFFT1),cb(MAXFFT1) !FFTs of raw x,y data complex ca(MAXFFT1),cb(MAXFFT1) !FFTs of raw x,y data
@ -25,10 +27,11 @@ subroutine q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, &
real*8 fcenter,freq0 real*8 fcenter,freq0
character*12 mycall0,hiscall0 character*12 mycall0,hiscall0
character*12 mycall,hiscall character*12 mycall,hiscall
character*6 hisgrid character*6 mygrid,hisgrid
character*4 grid4 character*4 grid4
character*80 line character*80 line
character*80 wsjtx_dir character*80 wsjtx_dir
character*1 cp,cmode*2
common/cacb/ca,cb common/cacb/ca,cb
save save
@ -88,10 +91,14 @@ subroutine q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, &
! 96000 5376000 0.017857143 336000 6000.000 ! 96000 5376000 0.017857143 336000 6000.000
! 95238 5120000 0.018601172 322560 5999.994 ! 95238 5120000 0.018601172 322560 5999.994
if(ipol.eq.1) cz(0:MAXFFT2-1)=cx poldeg=0.
if(ipol.eq.2) cz(0:MAXFFT2-1)=0.707*(cx+cy) if(xpol) then
if(ipol.eq.3) cz(0:MAXFFT2-1)=cy poldeg=sync(ipk)%pol
if(ipol.eq.4) cz(0:MAXFFT2-1)=0.707*(cx-cy) cz(0:MAXFFT2-1)=cos(poldeg/RAD)*cx + sin(poldeg/RAD)*cy
else
cz(0:MAXFFT2-1)=cx
endif
cz(MAXFFT2)=0. cz(MAXFFT2)=0.
! Roll off below 500 Hz and above 2500 Hz. ! Roll off below 500 Hz and above 2500 Hz.
ja=nint(500.0/df) ja=nint(500.0/df)
@ -136,21 +143,30 @@ subroutine q65b(nutc,nqd,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, &
if(nsnr0.gt.-99) then if(nsnr0.gt.-99) then
nq65df=nint(1000*(0.001*k0*df+nkhz_center-48.0+1.000-1.27046-ikhz))-nfcal nq65df=nint(1000*(0.001*k0*df+nkhz_center-48.0+1.000-1.27046-ikhz))-nfcal
nq65df=nq65df + nfreq0 - 1000 nq65df=nq65df + nfreq0 - 1000
npol=nint(poldeg)
if(nxant.ne.0) then
npol=npol-45
if(npol.lt.0) npol=npol+180
endif
call txpol(xpol,msg0(1:22),mygrid,npol,nxant,ntxpol,cp)
if(nqd.eq.1 .and. abs(nq65df-mousedf).lt.ntol) then if(nqd.eq.1 .and. abs(nq65df-mousedf).lt.ntol) then
write(line,1020) ikhz,nq65df,45*(ipol-1),nutc,xdt0,nsnr0,msg0(1:27),cq0 write(line,1020) ikhz,nq65df,npol,nutc,xdt0,nsnr0,msg0(1:27),cq0, &
1020 format('!',i3.3,i5,i4,i6.4,f5.1,i5,' : ',a27,a3) ntxpol,cp
1020 format('!',i3.3,i5,i4,i6.4,f5.1,i5,' : ',a27,a3,i4,1x,a1)
write(*,1100) trim(line) write(*,1100) trim(line)
1100 format(a) 1100 format(a)
endif endif
! Write to lu 26, for Messages and Band Map windows ! Write to lu 26, for Messages and Band Map windows
write(26,1014) freq0,nq65df,0,0,0,xdt0,45*(ipol-1),0, &
nsnr0,nutc,msg0(1:22),':',char(ichar('A') + mode_q65-1) cmode=': '
1014 format(f8.3,i5,3i3,f5.1,i4,i3,i4,i5.4,4x,a22,2x,a1,3x,':',a1) cmode(2:2)=char(ichar('A') + mode_q65-1)
write(26,1014) freq0,nq65df,0,0,0,xdt0,npol,0, &
nsnr0,nutc,msg0(1:22),':',cp,cmode
1014 format(f8.3,i5,3i3,f5.1,i4,i3,i4,i5.4,4x,a22,1x,2a1,2x,a2)
! Write to file map65_rx.log: ! Write to file map65_rx.log:
write(21,1110) freq0,nq65df,xdt0,45*(ipol-1),nsnr0,nutc,msg0(1:28),cq0 write(21,1110) freq0,nq65df,xdt0,npol,nsnr0,nutc,msg0(1:28),cq0
1110 format(f8.3,i5,f5.1,2i4,i5.4,2x,a28,': A',2x,a3) 1110 format(f8.3,i5,f5.1,2i4,i5.4,2x,a28,': A',2x,a3)
endif endif

View File

@ -41,7 +41,7 @@ program synctest
call timer('synctest',0) call timer('synctest',0)
call timer('get_cand',0) call timer('get_cand',0)
call get_candidates(ss,savg,nfa,nfb,nts_jt65,nts_q65,cand,ncand) call get_candidates(ss,savg,.true.,nfa,nfb,nts_jt65,nts_q65,cand,ncand)
call timer('get_cand',1) call timer('get_cand',1)
do k=1,ncand do k=1,ncand

33
map65/libm65/txpol.f90 Normal file
View File

@ -0,0 +1,33 @@
subroutine txpol(xpol,decoded,mygrid,npol,nxant,ntxpol,cp)
! If Tx station's grid is in decoded message, compute optimum TxPol
character*22 decoded
character*6 mygrid,grid
character*1 cp
logical xpol
ntxpol=0
i1=index(decoded,' ')
i2=index(decoded(i1+1:),' ') + i1
grid=' '
if(i2.ge.8 .and. i2.le.18) grid=decoded(i2+1:i2+4)//'mm'
ntxpol=0
cp=' '
if(xpol .and.grid(1:4).ne.'RR73') then
if(grid(1:1).ge.'A' .and. grid(1:1).le.'R' .and. &
grid(2:2).ge.'A' .and. grid(2:2).le.'R' .and. &
grid(3:3).ge.'0' .and. grid(3:3).le.'9' .and. &
grid(4:4).ge.'0' .and. grid(4:4).le.'9') then
ntxpol=mod(npol-nint(2.0*dpol(mygrid,grid))+720,180)
if(nxant.eq.0) then
cp='H'
if(ntxpol.gt.45 .and. ntxpol.le.135) cp='V'
else
cp='/'
if(ntxpol.ge.90 .and. ntxpol.lt.180) cp='\'
endif
endif
endif
return
end subroutine txpol

View File

@ -4,12 +4,14 @@ module wideband_sync
real :: snr !Relative S/N of sync detection real :: snr !Relative S/N of sync detection
real :: f !Freq of sync tone, 0 to 96000 Hz real :: f !Freq of sync tone, 0 to 96000 Hz
real :: xdt !DT of matching sync pattern, -1.0 to +4.0 s real :: xdt !DT of matching sync pattern, -1.0 to +4.0 s
real :: pol !Polarization angle, degrees
integer :: ipol !Polarization angle, 1 to 4 ==> 0, 45, 90, 135 deg integer :: ipol !Polarization angle, 1 to 4 ==> 0, 45, 90, 135 deg
integer :: iflip !Sync type: JT65 = +/- 1, Q65 = 0 integer :: iflip !Sync type: JT65 = +/- 1, Q65 = 0
end type candidate end type candidate
type sync_dat type sync_dat
real :: ccfmax real :: ccfmax
real :: xdt real :: xdt
real :: pol
integer :: ipol integer :: ipol
integer :: iflip integer :: iflip
logical :: birdie logical :: birdie
@ -17,12 +19,13 @@ module wideband_sync
parameter (NFFT=32768) parameter (NFFT=32768)
parameter (MAX_CANDIDATES=50) parameter (MAX_CANDIDATES=50)
parameter (SNR1_THRESHOLD=4.5)
type(sync_dat) :: sync(NFFT) type(sync_dat) :: sync(NFFT)
integer nkhz_center integer nkhz_center
contains contains
subroutine get_candidates(ss,savg,nfa,nfb,nts_jt65,nts_q65,cand,ncand) subroutine get_candidates(ss,savg,xpol,nfa,nfb,nts_jt65,nts_q65,cand,ncand)
! Search symbol spectra ss() over frequency range nfa to nfb (in kHz) for ! Search symbol spectra ss() over frequency range nfa to nfb (in kHz) for
! JT65 and Q65 sync patterns. The nts_* variables are the submode tone ! JT65 and Q65 sync patterns. The nts_* variables are the submode tone
@ -33,7 +36,7 @@ subroutine get_candidates(ss,savg,nfa,nfb,nts_jt65,nts_q65,cand,ncand)
real ss(4,322,NFFT),savg(4,NFFT) real ss(4,322,NFFT),savg(4,NFFT)
real pavg(-20:20) real pavg(-20:20)
integer indx(NFFT) integer indx(NFFT)
logical skip logical xpol,skip
type(candidate) :: cand(MAX_CANDIDATES) type(candidate) :: cand(MAX_CANDIDATES)
do j=322,1,-1 !Find end of data in ss() do j=322,1,-1 !Find end of data in ss()
@ -41,7 +44,7 @@ subroutine get_candidates(ss,savg,nfa,nfb,nts_jt65,nts_q65,cand,ncand)
enddo enddo
jz=j jz=j
call wb_sync(ss,savg,jz,nfa,nfb) call wb_sync(ss,savg,xpol,jz,nfa,nfb)
tstep=2048.0/11025.0 !0.185760 s: 0.5*tsym_jt65, 0.3096*tsym_q65 tstep=2048.0/11025.0 !0.185760 s: 0.5*tsym_jt65, 0.3096*tsym_q65
df3=96000.0/NFFT df3=96000.0/NFFT
@ -56,8 +59,7 @@ call wb_sync(ss,savg,jz,nfa,nfb)
n=indx(iz+1-i) + ia - 1 n=indx(iz+1-i) + ia - 1
f0=0.001*(n-1)*df3 f0=0.001*(n-1)*df3
snr1=sync(n)%ccfmax snr1=sync(n)%ccfmax
! print*,'=A',f0,snr1 if(snr1.lt.SNR1_THRESHOLD) exit
if(snr1.lt.4.5) exit
flip=sync(n)%iflip flip=sync(n)%iflip
if(flip.ne.0.0 .and. nts_jt65.eq.0) cycle if(flip.ne.0.0 .and. nts_jt65.eq.0) cycle
if(flip.eq.0.0 .and. nts_q65.eq.0) cycle if(flip.eq.0.0 .and. nts_q65.eq.0) cycle
@ -94,6 +96,7 @@ call wb_sync(ss,savg,jz,nfa,nfb)
cand(k)%snr=snr1 cand(k)%snr=snr1
cand(k)%f=f0 cand(k)%f=f0
cand(k)%xdt=sync(n)%xdt cand(k)%xdt=sync(n)%xdt
cand(k)%pol=sync(n)%pol
cand(k)%ipol=sync(n)%ipol cand(k)%ipol=sync(n)%ipol
cand(k)%iflip=nint(flip) cand(k)%iflip=nint(flip)
if(k.ge.MAX_CANDIDATES) exit if(k.ge.MAX_CANDIDATES) exit
@ -103,18 +106,21 @@ call wb_sync(ss,savg,jz,nfa,nfb)
return return
end subroutine get_candidates end subroutine get_candidates
subroutine wb_sync(ss,savg,jz,nfa,nfb) subroutine wb_sync(ss,savg,xpol,jz,nfa,nfb)
! Compute "orange sync curve" using the Q65 sync pattern ! Compute "orange sync curve" using the Q65 sync pattern
use timer_module, only: timer
parameter (NFFT=32768) parameter (NFFT=32768)
parameter (LAGMAX=30) parameter (LAGMAX=30)
real ss(4,322,NFFT) real ss(4,322,NFFT)
real savg(4,NFFT) real savg(4,NFFT)
real savg_med(4) real savg_med(4)
logical first real ccf4(4),ccf4best(4),a(3)
logical first,xpol
integer isync(22) integer isync(22)
integer jsync0(63),jsync1(63) integer jsync0(63),jsync1(63)
integer ip(1)
! Q65 sync symbols ! Q65 sync symbols
data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/
@ -147,12 +153,14 @@ subroutine wb_sync(ss,savg,jz,nfa,nfb)
df3=96000.0/NFFT df3=96000.0/NFFT
ia=nint(1000*nfa/df3) + 1 !Flat frequency range for WSE converters ia=nint(1000*nfa/df3) + 1 !Flat frequency range for WSE converters
ib=nint(1000*nfb/df3) + 1 ib=nint(1000*nfb/df3) + 1
npol=1
if(xpol) npol=4
do i=1,4 do i=1,npol
call pctile(savg(i,ia:ib),ib-ia+1,50,savg_med(i)) call pctile(savg(i,ia:ib),ib-ia+1,50,savg_med(i))
enddo enddo
! do i=ia,ib ! do i=ia,ib
! write(14,3014) 0.001*(i-1)*df3,savg(1:4,i) ! write(14,3014) 0.001*(i-1)*df3,savg(1:npol,i)
!3014 format(5f10.3) !3014 format(5f10.3)
! enddo ! enddo
@ -162,57 +170,83 @@ subroutine wb_sync(ss,savg,jz,nfa,nfb)
do i=ia,ib do i=ia,ib
ccfmax=0. ccfmax=0.
do ipol=1,4 do lag=0,LAGMAX
do lag=0,LAGMAX
ccf=0. ccf=0.
do j=1,22 ccf4=0.
k=isync(j) + lag do j=1,22 !Test for Q65 sync
ccf=ccf + ss(ipol,k,i+1) + ss(ipol,k+1,i+1) + ss(ipol,k+2,i+1) k=isync(j) + lag
enddo ccf4(1:npol)=ccf4(1:npol) + ss(1:npol,k,i+1) + &
ccf=ccf - savg(ipol,i+1)*3*22/float(jz) ss(1:npol,k+1,i+1) + ss(1:npol,k+2,i+1)
if(ccf.gt.ccfmax) then enddo
ipolbest=ipol ccf4(1:npol)=ccf4(1:npol) - savg(1:npol,i+1)*3*22/float(jz)
lagbest=lag ccf=maxval(ccf4)
ccfmax=ccf ip=maxloc(ccf4)
flip=0. ipol=ip(1)
endif if(ccf.gt.ccfmax) then
ipolbest=ipol
lagbest=lag
ccfmax=ccf
ccf4best=ccf4
flip=0.
endif
ccf=0. ccf=0.
do j=1,63 ccf4=0.
k=jsync0(j) + lag do j=1,63 !Test for JT65 sync, std msg
ccf=ccf + ss(ipol,k,i+1) + ss(ipol,k+1,i+1) k=jsync0(j) + lag
enddo ccf4(1:npol)=ccf4(1:npol) + ss(1:npol,k,i+1) + ss(1:npol,k+1,i+1)
ccf=ccf - savg(ipol,i+1)*2*63/float(jz) enddo
if(ccf.gt.ccfmax) then ccf4(1:npol)=ccf4(1:npol) - savg(1:npol,i+1)*2*63/float(jz)
ipolbest=ipol ccf=maxval(ccf4)
lagbest=lag ip=maxloc(ccf4)
ccfmax=ccf ipol=ip(1)
flip=1.0 if(ccf.gt.ccfmax) then
endif ipolbest=ipol
lagbest=lag
ccfmax=ccf
ccf4best=ccf4
flip=1.0
endif
ccf=0. ccf=0.
do j=1,63 ccf4=0.
k=jsync1(j) + lag do j=1,63 !Test for JT65 sync, OOO msg
ccf=ccf + ss(ipol,k,i+1) + ss(ipol,k+1,i+1) k=jsync1(j) + lag
enddo ccf4(1:npol)=ccf4(1:npol) + ss(1:npol,k,i+1) + ss(1:npol,k+1,i+1)
ccf=ccf - savg(ipol,i+1)*2*63/float(jz) enddo
if(ccf.gt.ccfmax) then ccf4(1:npol)=ccf4(1:npol) - savg(1:npol,i+1)*2*63/float(jz)
ipolbest=ipol ccf=maxval(ccf4)
lagbest=lag ip=maxloc(ccf4)
ccfmax=ccf ipol=ip(1)
flip=-1.0 if(ccf.gt.ccfmax) then
endif ipolbest=ipol
lagbest=lag
ccfmax=ccf
ccf4best=ccf4
flip=-1.0
endif
enddo ! lag enddo ! lag
enddo !ipol
poldeg=0.
if(xpol .and. ccfmax.ge.SNR1_THRESHOLD) then
call polfit(ccf4best,4,a)
poldeg=a(3)
endif
sync(i)%ccfmax=ccfmax sync(i)%ccfmax=ccfmax
sync(i)%xdt=lagbest*tstep-1.0 sync(i)%xdt=lagbest*tstep-1.0
sync(i)%pol=poldeg
sync(i)%ipol=ipolbest sync(i)%ipol=ipolbest
sync(i)%iflip=flip sync(i)%iflip=flip
sync(i)%birdie=.false. sync(i)%birdie=.false.
if(ccfmax/(savg(ipolbest,i)/savg_med(ipolbest)).lt.3.0) sync(i)%birdie=.true. if(ccfmax/(savg(ipolbest,i)/savg_med(ipolbest)).lt.3.0) sync(i)%birdie=.true.
! if(sync(i)%iflip.eq.0 .and. sync(i)%ccfmax .gt. 20.0) then
! write(50,3050) i,lagbest,sync(i)%ccfmax,sync(i)%xdt,sync(i)%ipol, &
! sync(i)%birdie,ccf4best
!3050 format(2i5,f10.3,f8.2,i5,1x,L3,4f7.1)
! endif
enddo ! i (frequency bin) enddo ! i (frequency bin)
! do i=ia,ib ! do i=ia,ib
@ -223,7 +257,6 @@ subroutine wb_sync(ss,savg,jz,nfa,nfb)
call pctile(sync(ia:ib)%ccfmax,ib-ia+1,50,base) call pctile(sync(ia:ib)%ccfmax,ib-ia+1,50,base)
sync(ia:ib)%ccfmax=sync(ia:ib)%ccfmax/base sync(ia:ib)%ccfmax=sync(ia:ib)%ccfmax/base
! print*,base
return return
end subroutine wb_sync end subroutine wb_sync

View File

@ -19,7 +19,7 @@ int main(int argc, char *argv[])
QApplication a {argc, argv}; QApplication a {argc, argv};
// Override programs executable basename as application name. // Override programs executable basename as application name.
a.setApplicationName ("MAP65"); a.setApplicationName ("MAP65");
a.setApplicationVersion ("3.0.0-rc1"); a.setApplicationVersion ("3.0.0-rc2");
// switch off as we share an Info.plist file with WSJT-X // switch off as we share an Info.plist file with WSJT-X
a.setAttribute (Qt::AA_DontUseNativeMenuBar); a.setAttribute (Qt::AA_DontUseNativeMenuBar);
MainWindow w; MainWindow w;

View File

@ -23,7 +23,7 @@
#define NFFT 32768 #define NFFT 32768
short int iwave[2*60*11025]; //Wave file for Tx audio short int iwave[2*60*12000]; //Wave file for Tx audio
int nwave; //Length of Tx waveform int nwave; //Length of Tx waveform
bool btxok; //True if OK to transmit bool btxok; //True if OK to transmit
bool bTune; bool bTune;

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>635</width> <width>635</width>
<height>512</height> <height>523</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -1704,7 +1704,7 @@ p, li { white-space: pre-wrap; }
<customwidget> <customwidget>
<class>DisplayText</class> <class>DisplayText</class>
<extends>QTextBrowser</extends> <extends>QTextBrowser</extends>
<header>displaytext.h</header> <header>widgets/displaytext.h</header>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources/> <resources/>

View File

@ -274,7 +274,7 @@ void CPlotter::UTCstr()
ihr=imin/60; ihr=imin/60;
imin=imin % 60; imin=imin % 60;
} }
m_sutc = QString {"%1:%2"}.arg (ihr, 2).arg (imin, 2); m_sutc = QString {"%1:%2"}.arg (ihr,2,10,QLatin1Char('0')).arg (imin,2,10,QLatin1Char('0'));
} }
void CPlotter::DrawOverlay() //DrawOverlay() void CPlotter::DrawOverlay() //DrawOverlay()

View File

@ -1,45 +1,52 @@
#include "soundin.h" #include "soundin.h"
#include <stdexcept>
#ifdef Q_OS_WIN32
#include <windows.h>
#else
#include <sys/socket.h>
#endif
#define NFFT 32768 #define NFFT 32768
#define FRAMES_PER_BUFFER 1024 #define FRAMES_PER_BUFFER 1024
extern "C" {
#include <portaudio.h> #include <portaudio.h>
extern struct { extern "C"
double d8[2*60*96000]; //This is "common/datcom/..." in fortran {
float ss[4*322*NFFT]; struct
float savg[4*NFFT]; {
double fcenter; double d8[2*60*96000]; //This is "common/datcom/..." in fortran
int nutc; float ss[4*322*NFFT];
int idphi; //Phase correction for Y pol'n, degrees float savg[4*NFFT];
int mousedf; //User-selected DF double fcenter;
int mousefqso; //User-selected QSO freq (kHz) int nutc;
int nagain; //1 ==> decode only at fQSO +/- Tol int idphi; //Phase correction for Y pol'n, degrees
int ndepth; //How much hinted decoding to do? int mousedf; //User-selected DF
int ndiskdat; //1 ==> data read from *.tf2 or *.iq file int mousefqso; //User-selected QSO freq (kHz)
int neme; //Hinted decoding tries only for EME calls int nagain; //1 ==> decode only at fQSO +/- Tol
int newdat; //1 ==> new data, must do long FFT int ndepth; //How much hinted decoding to do?
int nfa; //Low decode limit (kHz) int ndiskdat; //1 ==> data read from *.tf2 or *.iq file
int nfb; //High decode limit (kHz) int neme; //Hinted decoding tries only for EME calls
int nfcal; //Frequency correction, for calibration (Hz) int newdat; //1 ==> new data, must do long FFT
int nfshift; //Shift of displayed center freq (kHz) int nfa; //Low decode limit (kHz)
int mcall3; //1 ==> CALL3.TXT has been modified int nfb; //High decode limit (kHz)
int ntimeout; //Max for timeouts in Messages and BandMap int nfcal; //Frequency correction, for calibration (Hz)
int ntol; //+/- decoding range around fQSO (Hz) int nfshift; //Shift of displayed center freq (kHz)
int nxant; //1 ==> add 45 deg to measured pol angle int mcall3; //1 ==> CALL3.TXT has been modified
int map65RxLog; //Flags to control log files int ntimeout; //Max for timeouts in Messages and BandMap
int nfsample; //Input sample rate int ntol; //+/- decoding range around fQSO (Hz)
int nxpol; //1 if using xpol antennas, 0 otherwise int nxant; //1 ==> add 45 deg to measured pol angle
int mode65; //JT65 sub-mode: A=1, B=2, C=4 int map65RxLog; //Flags to control log files
int nfast; //1No longer used int nfsample; //Input sample rate
int nsave; //Number of s3(64,63) spectra saved int nxpol; //1 if using xpol antennas, 0 otherwise
char mycall[12]; int mode65; //JT65 sub-mode: A=1, B=2, C=4
char mygrid[6]; int nfast; //1No longer used
char hiscall[12]; int nsave; //Number of s3(64,63) spectra saved
char hisgrid[6]; char mycall[12];
char datetime[20]; char mygrid[6];
} datcom_; char hiscall[12];
char hisgrid[6];
char datetime[20];
} datcom_;
} }
typedef struct typedef struct
@ -133,6 +140,26 @@ extern "C" int a2dCallback( const void *inputBuffer, void *outputBuffer,
return paContinue; return paContinue;
} }
namespace
{
struct COMWrapper
{
explicit COMWrapper ()
{
#ifdef Q_OS_WIN32
// required because Qt only does this for GUI thread
CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
#endif
}
~COMWrapper ()
{
#ifdef Q_OS_WIN32
CoUninitialize ();
#endif
}
};
}
void SoundInThread::run() //SoundInThread::run() void SoundInThread::run() //SoundInThread::run()
{ {
quitExecution = false; quitExecution = false;
@ -144,8 +171,10 @@ void SoundInThread::run() //SoundInThread::run()
return; return;
} }
//---------------------------------------------------- Soundcard Setup COMWrapper c;
// qDebug() << "Start souncard input";
//---------------------------------------------------- Soundcard Setup
// qDebug() << "Start souncard input";
PaError paerr; PaError paerr;
PaStreamParameters inParam; PaStreamParameters inParam;
@ -158,15 +187,27 @@ void SoundInThread::run() //SoundInThread::run()
udata.iqswap=m_IQswap; udata.iqswap=m_IQswap;
udata.b10db=m_10db; udata.b10db=m_10db;
auto device_info = Pa_GetDeviceInfo (m_nDevIn);
inParam.device=m_nDevIn; //### Input Device Number ### inParam.device=m_nDevIn; //### Input Device Number ###
inParam.channelCount=2*m_nrx; //Number of analog channels inParam.channelCount=2*m_nrx; //Number of analog channels
inParam.sampleFormat=paFloat32; //Get floats from Portaudio inParam.sampleFormat=paFloat32; //Get floats from Portaudio
inParam.suggestedLatency=0.05; inParam.suggestedLatency=device_info->defaultHighInputLatency;
inParam.hostApiSpecificStreamInfo=NULL; inParam.hostApiSpecificStreamInfo=NULL;
paerr=Pa_IsFormatSupported(&inParam,NULL,96000.0); paerr=Pa_IsFormatSupported(&inParam,NULL,96000.0);
if(paerr<0) { if(paerr<0) {
emit error("PortAudio says requested soundcard format not supported."); QString error_message;
if (paUnanticipatedHostError == paerr)
{
auto const * last_host_error = Pa_GetLastHostErrorInfo ();
error_message = QString {"PortAudio Host API error: %1"}.arg (last_host_error->errorText);
}
else
{
error_message = "PortAudio says requested soundcard format not supported.";
}
emit error(error_message);
// return; // return;
} }
paerr=Pa_OpenStream(&inStream, //Input stream paerr=Pa_OpenStream(&inStream, //Input stream

View File

@ -6,12 +6,6 @@
#include <QDebug> #include <QDebug>
#include <valarray> #include <valarray>
#ifdef Q_OS_WIN32
#include <winsock.h>
#else
#include <sys/socket.h>
#endif //Q_OS_WIN32
// Thread gets audio data from soundcard and signals when a buffer of // Thread gets audio data from soundcard and signals when a buffer of
// specified size is available. // specified size is available.
class SoundInThread : public QThread class SoundInThread : public QThread

View File

@ -1,10 +1,12 @@
#include "soundout.h" #include "soundout.h"
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#define FRAMES_PER_BUFFER 256 #define FRAMES_PER_BUFFER 256
extern "C" {
#include <portaudio.h> #include <portaudio.h>
}
extern float gran(); //Noise generator (for tests only) extern float gran(); //Noise generator (for tests only)
@ -120,18 +122,42 @@ extern "C" int d2aCallback(const void * /*inputBuffer*/, void *outputBuffer,
return 0; return 0;
} }
namespace
{
struct COMWrapper
{
explicit COMWrapper ()
{
#ifdef Q_OS_WIN32
// required because Qt only does this for GUI thread
CoInitializeEx (nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
#endif
}
~COMWrapper ()
{
#ifdef Q_OS_WIN32
CoUninitialize ();
#endif
}
};
}
void SoundOutThread::run() void SoundOutThread::run()
{ {
COMWrapper c;
PaError paerr; PaError paerr;
PaStreamParameters outParam; PaStreamParameters outParam;
PaStream *outStream; PaStream *outStream;
paUserData udata; paUserData udata;
quitExecution = false; quitExecution = false;
auto device_info = Pa_GetDeviceInfo (m_nDevOut);
outParam.device=m_nDevOut; //Output device number outParam.device=m_nDevOut; //Output device number
outParam.channelCount=2; //Number of analog channels outParam.channelCount=2; //Number of analog channels
outParam.sampleFormat=paInt16; //Send short ints to PortAudio outParam.sampleFormat=paInt16; //Send short ints to PortAudio
outParam.suggestedLatency=0.05; outParam.suggestedLatency=device_info->defaultLowOutputLatency;
outParam.hostApiSpecificStreamInfo=NULL; outParam.hostApiSpecificStreamInfo=NULL;
udata.nTRperiod=m_TRperiod; udata.nTRperiod=m_TRperiod;

View File

@ -14,7 +14,7 @@ auto CallsignValidator::validate (QString& input, int& pos) const -> State
input.remove (0, 1); input.remove (0, 1);
if (pos > 0) --pos; if (pos > 0) --pos;
} }
while (input.size () && input[input.size ()].isSpace ()) while (input.size () && input[input.size () - 1].isSpace ())
{ {
if (pos > input.size ()) --pos; if (pos > input.size ()) --pos;
input.chop (1); input.chop (1);

27
widgets/BandComboBox.cpp Normal file
View File

@ -0,0 +1,27 @@
#include "BandComboBox.hpp"
#include <QAbstractItemView>
#include <QScrollBar>
#include <QDebug>
#include "models/FrequencyList.hpp"
BandComboBox::BandComboBox (QWidget * parent)
: QComboBox {parent}
{
}
// Fix up broken QComboBox item view rendering which doesn't allow for
// a vertical scroll bar in width calculations and ends up eliding the
// item text.
void BandComboBox::showPopup ()
{
auto minimum_width = view ()->sizeHintForColumn (FrequencyList_v2::frequency_mhz_column);
if (count () > maxVisibleItems ())
{
// for some as yet unknown reason, in FT8 mode the scrollbar
// width is oversize on the first call here
minimum_width += view ()->verticalScrollBar ()->width ();
}
view ()->setMinimumWidth (minimum_width);
QComboBox::showPopup ();
}

16
widgets/BandComboBox.hpp Normal file
View File

@ -0,0 +1,16 @@
#ifndef BAND_COMBO_BOX_HPP__
#define BAND_COMBO_BOX_HPP__
#include <QComboBox>
class BandComboBox
: public QComboBox
{
public:
explicit BandComboBox (QWidget * = nullptr);
private:
void showPopup () override;
};
#endif

View File

@ -45,6 +45,7 @@
#include <QRandomGenerator> #include <QRandomGenerator>
#endif #endif
#include "helper_functions.h"
#include "revision_utils.hpp" #include "revision_utils.hpp"
#include "qt_helpers.hpp" #include "qt_helpers.hpp"
#include "Network/NetworkAccessManager.hpp" #include "Network/NetworkAccessManager.hpp"
@ -274,7 +275,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_freqNominal {0}, m_freqNominal {0},
m_freqTxNominal {0}, m_freqTxNominal {0},
m_reverse_Doppler {"1" == env.value ("WSJT_REVERSE_DOPPLER", "0")}, m_reverse_Doppler {"1" == env.value ("WSJT_REVERSE_DOPPLER", "0")},
m_s6 {0.},
m_tRemaining {0.}, m_tRemaining {0.},
m_TRperiod {60.0}, m_TRperiod {60.0},
m_DTtol {3.0}, m_DTtol {3.0},
@ -293,7 +293,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_idleMinutes {0}, m_idleMinutes {0},
m_nSubMode {0}, m_nSubMode {0},
m_nclearave {1}, m_nclearave {1},
m_nseq {0},
m_nWSPRdecodes {0}, m_nWSPRdecodes {0},
m_k0 {9999999}, m_k0 {9999999},
m_nPick {0}, m_nPick {0},
@ -755,10 +754,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
ui->bandComboBox->setModel (m_config.frequencies ()); ui->bandComboBox->setModel (m_config.frequencies ());
ui->bandComboBox->setModelColumn (FrequencyList_v2::frequency_mhz_column); ui->bandComboBox->setModelColumn (FrequencyList_v2::frequency_mhz_column);
// combo box drop down width defaults to the line edit + decorator width,
// here we change that to the column width size hint of the model column
ui->bandComboBox->view ()->setMinimumWidth (ui->bandComboBox->view ()->sizeHintForColumn (FrequencyList_v2::frequency_mhz_column));
// Enable live band combo box entry validation and action. // Enable live band combo box entry validation and action.
auto band_validator = new LiveFrequencyValidator {ui->bandComboBox auto band_validator = new LiveFrequencyValidator {ui->bandComboBox
, m_config.bands () , m_config.bands ()
@ -928,7 +923,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
QByteArray cfname=fname.toLocal8Bit(); QByteArray cfname=fname.toLocal8Bit();
fftwf_import_wisdom_from_filename(cfname); fftwf_import_wisdom_from_filename(cfname);
//genStdMsgs(m_rpt);
m_ntx = 6; m_ntx = 6;
ui->txrb6->setChecked(true); ui->txrb6->setChecked(true);
@ -1008,7 +1002,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_fastGraph->setMode(m_mode); m_fastGraph->setMode(m_mode);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
connect (&minuteTimer, &QTimer::timeout, this, &MainWindow::on_the_minute); connect (&minuteTimer, &QTimer::timeout, this, &MainWindow::on_the_minute);
minuteTimer.setSingleShot (true); minuteTimer.setSingleShot (true);
@ -1031,6 +1024,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
void MainWindow::not_GA_warning_message () void MainWindow::not_GA_warning_message ()
{ {
MessageBox::critical_message (this, MessageBox::critical_message (this,
"This is a pre-release version of WSJT-X 2.5.0 made\n" "This is a pre-release version of WSJT-X 2.5.0 made\n"
"available for testing purposes. By design it will\n" "available for testing purposes. By design it will\n"
@ -1139,7 +1133,6 @@ void MainWindow::writeSettings()
m_settings->beginGroup("Common"); m_settings->beginGroup("Common");
m_settings->setValue("Mode",m_mode); m_settings->setValue("Mode",m_mode);
m_settings->setValue("ModeTx",m_modeTx);
m_settings->setValue("SaveNone",ui->actionNone->isChecked()); m_settings->setValue("SaveNone",ui->actionNone->isChecked());
m_settings->setValue("SaveDecoded",ui->actionSave_decoded->isChecked()); m_settings->setValue("SaveDecoded",ui->actionSave_decoded->isChecked());
m_settings->setValue("SaveAll",ui->actionSave_all->isChecked()); m_settings->setValue("SaveAll",ui->actionSave_all->isChecked());
@ -1238,7 +1231,6 @@ void MainWindow::readSettings()
m_settings->beginGroup("Common"); m_settings->beginGroup("Common");
m_mode=m_settings->value("Mode","JT9").toString(); m_mode=m_settings->value("Mode","JT9").toString();
m_modeTx=m_settings->value("ModeTx","JT9").toString();
ui->actionNone->setChecked(m_settings->value("SaveNone",true).toBool()); ui->actionNone->setChecked(m_settings->value("SaveNone",true).toBool());
ui->actionSave_decoded->setChecked(m_settings->value("SaveDecoded",false).toBool()); ui->actionSave_decoded->setChecked(m_settings->value("SaveDecoded",false).toBool());
ui->actionSave_all->setChecked(m_settings->value("SaveAll",false).toBool()); ui->actionSave_all->setChecked(m_settings->value("SaveAll",false).toBool());
@ -2201,17 +2193,13 @@ void MainWindow::keyPressEvent (QKeyEvent * e)
return; return;
} }
break; break;
case Qt::Key_Z: //### Recover from hung decode() ?? ### case Qt::Key_X:
if(e->modifiers() & Qt::AltModifier) { if(e->modifiers() & Qt::AltModifier) {
decodeDone(); // qDebug() << "Alt-X" << m_mode << m_TRperiod << m_nsps << m_bFast9
return; // << tx_duration(m_mode,m_TRperiod,m_nsps,m_bFast9);
} return;
break; case Qt::Key_PageUp: }
}
break;
case Qt::Key_PageDown:
band_changed(m_freqNominal-2000);
break; }
QMainWindow::keyPressEvent (e); QMainWindow::keyPressEvent (e);
} }
@ -2289,7 +2277,7 @@ void MainWindow::statusChanged()
if (!tmpGrid.size ()) tmpGrid="n/a"; // Not Available if (!tmpGrid.size ()) tmpGrid="n/a"; // Not Available
out << qSetRealNumberPrecision (12) << (m_freqNominal / 1.e6) out << qSetRealNumberPrecision (12) << (m_freqNominal / 1.e6)
<< ";" << m_mode << ";" << m_hisCall << ";" << ";" << m_mode << ";" << m_hisCall << ";"
<< ui->rptSpinBox->value() << ";" << m_modeTx << ";" << tmpGrid << ui->rptSpinBox->value() << ";" << m_mode << ";" << tmpGrid
#if QT_VERSION >= QT_VERSION_CHECK (5, 15, 0) #if QT_VERSION >= QT_VERSION_CHECK (5, 15, 0)
<< Qt::endl << Qt::endl
#else #else
@ -3142,7 +3130,6 @@ void MainWindow::decode() //decode()
if(dec_data.params.nutc < m_nutc0) m_RxLog = 1; //Date and Time to file "ALL.TXT". if(dec_data.params.nutc < m_nutc0) m_RxLog = 1; //Date and Time to file "ALL.TXT".
if(dec_data.params.newdat==1 and !m_diskData) m_nutc0=dec_data.params.nutc; if(dec_data.params.newdat==1 and !m_diskData) m_nutc0=dec_data.params.nutc;
dec_data.params.ntxmode=9; dec_data.params.ntxmode=9;
if(m_modeTx=="JT65") dec_data.params.ntxmode=65;
dec_data.params.nmode=9; dec_data.params.nmode=9;
if(m_mode=="JT65") dec_data.params.nmode=65; if(m_mode=="JT65") dec_data.params.nmode=65;
if(m_mode=="JT65") dec_data.params.ljt65apon = ui->actionEnable_AP_JT65->isVisible () && if(m_mode=="JT65") dec_data.params.ljt65apon = ui->actionEnable_AP_JT65->isVisible () &&
@ -3163,6 +3150,7 @@ void MainWindow::decode() //decode()
} }
if(m_mode=="FST4") dec_data.params.nmode=240; if(m_mode=="FST4") dec_data.params.nmode=240;
if(m_mode=="FST4W") dec_data.params.nmode=241; if(m_mode=="FST4W") dec_data.params.nmode=241;
dec_data.params.ntxmode=dec_data.params.nmode; // Is this used any more?
dec_data.params.ntrperiod=m_TRperiod; dec_data.params.ntrperiod=m_TRperiod;
dec_data.params.nsubmode=m_nSubMode; dec_data.params.nsubmode=m_nSubMode;
dec_data.params.minw=0; dec_data.params.minw=0;
@ -3807,42 +3795,14 @@ void MainWindow::guiUpdate()
static char message[38]; static char message[38];
static char msgsent[38]; static char msgsent[38];
double txDuration; double txDuration;
QString rt;
if(m_TRperiod==0) m_TRperiod=60.0; if(m_TRperiod==0) m_TRperiod=60.0;
txDuration=0.0; txDuration=tx_duration(m_mode,m_TRperiod,m_nsps,m_bFast9);
if(m_modeTx=="FT4") txDuration=1.0 + 105*576/12000.0; // FT4
if(m_modeTx=="FT8") txDuration=1.0 + 79*1920/12000.0; // FT8
if(m_modeTx=="JT4") txDuration=1.0 + 207.0*2520/11025.0; // JT4
if(m_modeTx=="JT9") txDuration=1.0 + 85.0*m_nsps/12000.0; // JT9
if(m_modeTx=="JT65") txDuration=1.0 + 126*4096/11025.0; // JT65
if(m_modeTx=="Q65") { // Q65
if(m_TRperiod==15) txDuration=0.5 + 85*1800/12000.0;
if(m_TRperiod==30) txDuration=0.5 + 85*3600/12000.0;
if(m_TRperiod==60) txDuration=1.0 + 85*7200/12000.0;
if(m_TRperiod==120) txDuration=1.0 + 85*16000/12000.0;
if(m_TRperiod==300) txDuration=1.0 + 85*41472/12000.0;
}
if(m_modeTx=="WSPR") txDuration=2.0 + 162*8192/12000.0; // WSPR
if(m_modeTx=="FST4" or m_mode=="FST4W") { //FST4, FST4W
if(m_TRperiod==15) txDuration=1.0 + 160*720/12000.0;
if(m_TRperiod==30) txDuration=1.0 + 160*1680/12000.0;
if(m_TRperiod==60) txDuration=1.0 + 160*3888/12000.0;
if(m_TRperiod==120) txDuration=1.0 + 160*8200/12000.0;
if(m_TRperiod==300) txDuration=1.0 + 160*21504/12000.0;
if(m_TRperiod==900) txDuration=1.0 + 160*66560/12000.0;
if(m_TRperiod==1800) txDuration=1.0 + 160*134400/12000.0;
}
if(m_mode=="MSK144" or m_bFast9) {
txDuration=m_TRperiod-0.25; // JT9-fast, MSK144
}
double tx1=0.0; double tx1=0.0;
double tx2=txDuration; double tx2=txDuration;
if(m_mode=="FT8" or m_mode=="FT4") icw[0]=0; //No CW ID in FT4 or FT8 mode if(m_mode=="FT8" or m_mode=="FT4") icw[0]=0; //No CW ID in FT4 or FT8 mode
if((icw[0]>0) and (!m_bFast9)) tx2 += icw[0]*2560.0/48000.0; //Full length including CW ID if((icw[0]>0) and (!m_bFast9)) tx2 += icw[0]*2560.0/48000.0; //Full length including CW ID
if(tx2>m_TRperiod) tx2=m_TRperiod; if(tx2>m_TRperiod) tx2=m_TRperiod;
if(!m_txFirst and m_mode!="WSPR" and m_mode!="FST4W") { if(!m_txFirst and m_mode!="WSPR" and m_mode!="FST4W") {
tx1 += m_TRperiod; tx1 += m_TRperiod;
tx2 += m_TRperiod; tx2 += m_TRperiod;
@ -3852,20 +3812,19 @@ void MainWindow::guiUpdate()
int nsec=ms/1000; int nsec=ms/1000;
double tsec=0.001*ms; double tsec=0.001*ms;
double t2p=fmod(tsec,2*m_TRperiod); double t2p=fmod(tsec,2*m_TRperiod);
m_s6=fmod(tsec,6.0); double s6=fmod(tsec,6.0);
m_nseq = fmod(double(nsec),m_TRperiod); int nseq = fmod(double(nsec),m_TRperiod);
m_tRemaining=m_TRperiod - fmod(tsec,m_TRperiod); m_tRemaining=m_TRperiod - fmod(tsec,m_TRperiod);
if(m_mode=="Echo") { if(m_mode=="Echo") {
txDuration=2.4;
tx1=0.0; tx1=0.0;
tx2=txDuration; tx2=txDuration;
if(m_auto and m_s6>4.0) m_bEchoTxOK=true; if(m_auto and s6>4.0) m_bEchoTxOK=true;
if(m_transmitting) m_bEchoTxed=true; if(m_transmitting) m_bEchoTxed=true;
} }
if(m_mode=="WSPR" or m_mode=="FST4W") { if(m_mode=="WSPR" or m_mode=="FST4W") {
if(m_nseq==0 and m_ntr==0) { //Decide whether to Tx or Rx if(nseq==0 and m_ntr==0) { //Decide whether to Tx or Rx
m_tuneup=false; //This is not an ATU tuneup m_tuneup=false; //This is not an ATU tuneup
bool btx = m_auto && m_WSPR_tx_next; // To Tx, we need m_auto and bool btx = m_auto && m_WSPR_tx_next; // To Tx, we need m_auto and
// scheduled transmit // scheduled transmit
@ -3940,7 +3899,7 @@ void MainWindow::guiUpdate()
tx_watchdog (true); // disable transmit tx_watchdog (true); // disable transmit
} }
float fTR=float((ms%int(1000.0*m_TRperiod)))/int(1000.0*m_TRperiod); double fTR=float((ms%int(1000.0*m_TRperiod)))/int(1000.0*m_TRperiod);
QString txMsg; QString txMsg;
if(m_ntx == 1) txMsg=ui->tx1->text(); if(m_ntx == 1) txMsg=ui->tx1->text();
@ -3952,7 +3911,7 @@ void MainWindow::guiUpdate()
int msgLength=txMsg.trimmed().length(); int msgLength=txMsg.trimmed().length();
if(msgLength==0 and !m_tune) on_stopTxButton_clicked(); if(msgLength==0 and !m_tune) on_stopTxButton_clicked();
if(g_iptt==0 and ((m_bTxTime and fTR<0.75 and msgLength>0) or m_tune)) { if(g_iptt==0 and ((m_bTxTime and (fTR < 0.75) and (msgLength>0)) or m_tune)) {
//### Allow late starts //### Allow late starts
icw[0]=m_ncw; icw[0]=m_ncw;
g_iptt = 1; g_iptt = 1;
@ -4006,7 +3965,7 @@ void MainWindow::guiUpdate()
} }
if((m_mode=="WSPR" or m_mode=="FST4W") and if((m_mode=="WSPR" or m_mode=="FST4W") and
((m_ntr==1 and m_rxDone) or (m_ntr==-1 and m_nseq>tx2))) { ((m_ntr==1 and m_rxDone) or (m_ntr==-1 and nseq>tx2))) {
if(m_monitoring) { if(m_monitoring) {
m_rxDone=false; m_rxDone=false;
} }
@ -4064,13 +4023,13 @@ void MainWindow::guiUpdate()
} else { } else {
if(m_QSOProgress==REPORT || m_QSOProgress==ROGER_REPORT) m_bSentReport=true; if(m_QSOProgress==REPORT || m_QSOProgress==ROGER_REPORT) m_bSentReport=true;
if(m_bSentReport and (m_QSOProgress<REPORT or m_QSOProgress>ROGER_REPORT)) m_bSentReport=false; if(m_bSentReport and (m_QSOProgress<REPORT or m_QSOProgress>ROGER_REPORT)) m_bSentReport=false;
if(m_modeTx=="JT4") gen4_(message, &ichk , msgsent, const_cast<int *> (itone), if(m_mode=="JT4") gen4_(message, &ichk , msgsent, const_cast<int *> (itone),
&m_currentMessageType, 22, 22); &m_currentMessageType, 22, 22);
if(m_modeTx=="JT9") gen9_(message, &ichk, msgsent, const_cast<int *> (itone), if(m_mode=="JT9") gen9_(message, &ichk, msgsent, const_cast<int *> (itone),
&m_currentMessageType, 22, 22); &m_currentMessageType, 22, 22);
if(m_modeTx=="JT65") gen65_(message, &ichk, msgsent, const_cast<int *> (itone), if(m_mode=="JT65") gen65_(message, &ichk, msgsent, const_cast<int *> (itone),
&m_currentMessageType, 22, 22); &m_currentMessageType, 22, 22);
if(m_modeTx=="Q65") { if(m_mode=="Q65") {
int i3=-1; int i3=-1;
int n3=-1; int n3=-1;
genq65_(message,&ichk,msgsent,const_cast<int *>(itone),&i3,&n3,37,37); genq65_(message,&ichk,msgsent,const_cast<int *>(itone),&i3,&n3,37,37);
@ -4089,15 +4048,15 @@ void MainWindow::guiUpdate()
genwave_(const_cast<int *>(itone),&nsym,&nsps4,&nwave, genwave_(const_cast<int *>(itone),&nsym,&nsps4,&nwave,
&fsample,&hmod,&f0,&icmplx,foxcom_.wave,foxcom_.wave); &fsample,&hmod,&f0,&icmplx,foxcom_.wave,foxcom_.wave);
} }
if(m_modeTx=="WSPR") genwspr_(message, msgsent, const_cast<int *> (itone), if(m_mode=="WSPR") genwspr_(message, msgsent, const_cast<int *> (itone),
22, 22); 22, 22);
if(m_modeTx=="MSK144" or m_modeTx=="FT8" or m_modeTx=="FT4" if(m_mode=="MSK144" or m_mode=="FT8" or m_mode=="FT4"
or m_modeTx=="FST4" or m_modeTx=="FST4W") { or m_mode=="FST4" or m_mode=="FST4W") {
char MyCall[6]; char MyCall[6];
char MyGrid[6]; char MyGrid[6];
::memcpy(MyCall, (m_config.my_callsign()+" ").toLatin1(), sizeof MyCall); ::memcpy(MyCall, (m_config.my_callsign()+" ").toLatin1(), sizeof MyCall);
::memcpy(MyGrid, (m_config.my_grid()+" ").toLatin1(), sizeof MyGrid); ::memcpy(MyGrid, (m_config.my_grid()+" ").toLatin1(), sizeof MyGrid);
if(m_modeTx=="MSK144") { if(m_mode=="MSK144") {
genmsk_128_90_(message, &ichk, msgsent, const_cast<int *> (itone), genmsk_128_90_(message, &ichk, msgsent, const_cast<int *> (itone),
&m_currentMessageType, 37, 37); &m_currentMessageType, 37, 37);
if(m_restart) { if(m_restart) {
@ -4107,7 +4066,7 @@ void MainWindow::guiUpdate()
} }
} }
if(m_modeTx=="FT8") { if(m_mode=="FT8") {
if(SpecOp::FOX==m_config.special_op_id() and ui->tabWidget->currentIndex()==1) { if(SpecOp::FOX==m_config.special_op_id() and ui->tabWidget->currentIndex()==1) {
foxTxSequencer(); foxTxSequencer();
} else { } else {
@ -4138,7 +4097,7 @@ void MainWindow::guiUpdate()
} }
} }
} }
if(m_modeTx=="FT4") { if(m_mode=="FT4") {
int ichk=0; int ichk=0;
char ft4msgbits[77]; char ft4msgbits[77];
genft4_(message, &ichk, msgsent, const_cast<char *> (ft4msgbits), genft4_(message, &ichk, msgsent, const_cast<char *> (ft4msgbits),
@ -4152,7 +4111,7 @@ void MainWindow::guiUpdate()
gen_ft4wave_(const_cast<int *>(itone),&nsym,&nsps,&fsample,&f0,foxcom_.wave, gen_ft4wave_(const_cast<int *>(itone),&nsym,&nsps,&fsample,&f0,foxcom_.wave,
foxcom_.wave,&icmplx,&nwave); foxcom_.wave,&icmplx,&nwave);
} }
if(m_modeTx=="FST4" or m_modeTx=="FST4W") { if(m_mode=="FST4" or m_mode=="FST4W") {
int ichk=0; int ichk=0;
int iwspr=0; int iwspr=0;
char fst4msgbits[101]; char fst4msgbits[101];
@ -4230,7 +4189,7 @@ void MainWindow::guiUpdate()
if(m_restart) { if(m_restart) {
write_all("Tx",m_currentMessage); write_all("Tx",m_currentMessage);
if (m_config.TX_messages ()) { if (m_config.TX_messages ()) {
ui->decodedTextBrowser2->displayTransmittedText(m_currentMessage.trimmed(),m_modeTx, ui->decodedTextBrowser2->displayTransmittedText(m_currentMessage.trimmed(),m_mode,
ui->TxFreqSpinBox->value(),m_bFastMode,m_TRperiod); ui->TxFreqSpinBox->value(),m_bFastMode,m_TRperiod);
} }
} }
@ -4314,6 +4273,7 @@ void MainWindow::guiUpdate()
m_sentFirst73 = false; m_sentFirst73 = false;
} }
} }
if (g_iptt == 1 && m_iptt0 == 0) { if (g_iptt == 1 && m_iptt0 == 0) {
auto const& current_message = QString::fromLatin1 (msgsent); auto const& current_message = QString::fromLatin1 (msgsent);
if(m_config.watchdog () && m_mode!="WSPR" && m_mode!="FST4W" if(m_config.watchdog () && m_mode!="WSPR" && m_mode!="FST4W"
@ -4328,7 +4288,7 @@ void MainWindow::guiUpdate()
if (m_config.TX_messages () && !m_tune && SpecOp::FOX!=m_config.special_op_id()) if (m_config.TX_messages () && !m_tune && SpecOp::FOX!=m_config.special_op_id())
{ {
ui->decodedTextBrowser2->displayTransmittedText(current_message.trimmed(), ui->decodedTextBrowser2->displayTransmittedText(current_message.trimmed(),
m_modeTx,ui->TxFreqSpinBox->value(),m_bFastMode,m_TRperiod); m_mode,ui->TxFreqSpinBox->value(),m_bFastMode,m_TRperiod);
} }
} }
@ -4346,15 +4306,14 @@ void MainWindow::guiUpdate()
transmitDisplay (true); transmitDisplay (true);
statusUpdate (); statusUpdate ();
} }
if(!m_btxok && m_btxok0 && g_iptt==1)
{ if(!m_btxok && m_btxok0 && g_iptt==1) {
stopTx(); stopTx();
if ("1" == m_env.value ("WSJT_TX_BOTH", "0")) if ("1" == m_env.value ("WSJT_TX_BOTH", "0")) {
{ m_txFirst = !m_txFirst;
m_txFirst = !m_txFirst; ui->txFirstCheckBox->setChecked (m_txFirst);
ui->txFirstCheckBox->setChecked (m_txFirst);
}
} }
}
if(m_startAnother) { if(m_startAnother) {
if(m_mode=="MSK144") { if(m_mode=="MSK144") {
@ -4368,16 +4327,16 @@ void MainWindow::guiUpdate()
} }
if(m_mode=="FT8" or m_mode=="MSK144" or m_mode=="FT4") { if(m_mode=="FT8" or m_mode=="MSK144" or m_mode=="FT4") {
if(ui->txrb1->isEnabled() and if(ui->txrb1->isEnabled() and
(SpecOp::NA_VHF==m_config.special_op_id() or (SpecOp::NA_VHF==m_config.special_op_id() or
SpecOp::FIELD_DAY==m_config.special_op_id() or SpecOp::FIELD_DAY==m_config.special_op_id() or
SpecOp::RTTY==m_config.special_op_id() or SpecOp::RTTY==m_config.special_op_id() or
SpecOp::WW_DIGI==m_config.special_op_id()) ) { SpecOp::WW_DIGI==m_config.special_op_id()) ) {
//We're in a contest-like mode other than EU_VHF: start QSO with Tx2. //We're in a contest-like mode other than EU_VHF: start QSO with Tx2.
ui->tx1->setEnabled(false); ui->tx1->setEnabled(false);
ui->txb1->setEnabled(false); ui->txb1->setEnabled(false);
} }
if(!ui->tx1->isEnabled() and SpecOp::EU_VHF==m_config.special_op_id()) { if(!ui->tx1->isEnabled() and SpecOp::EU_VHF==m_config.special_op_id()) {
//We're in EU_VHF mode: start QSO with Tx1. //We're in EU_VHF mode: start QSO with Tx1.
ui->tx1->setEnabled(true); ui->tx1->setEnabled(true);
ui->txb1->setEnabled(true); ui->txb1->setEnabled(true);
@ -4387,6 +4346,7 @@ void MainWindow::guiUpdate()
//Once per second (onesec) //Once per second (onesec)
if(nsec != m_sec0) { if(nsec != m_sec0) {
// qDebug() << "AAA" << nsec; // qDebug() << "AAA" << nsec;
if(m_mode=="FST4") chk_FST4_freq_range(); if(m_mode=="FST4") chk_FST4_freq_range();
m_currentBand=m_config.bands()->find(m_freqNominal); m_currentBand=m_config.bands()->find(m_freqNominal);
if( SpecOp::HOUND == m_config.special_op_id() ) { if( SpecOp::HOUND == m_config.special_op_id() ) {
@ -4399,7 +4359,7 @@ void MainWindow::guiUpdate()
progressBar.setFormat ("%v/%m"); progressBar.setFormat ("%v/%m");
if(m_auto and m_mode=="Echo" and m_bEchoTxOK) { if(m_auto and m_mode=="Echo" and m_bEchoTxOK) {
progressBar.setMaximum(3); progressBar.setMaximum(3);
progressBar.setValue(int(m_s6)); progressBar.setValue(int(s6));
} }
if(m_mode!="Echo") { if(m_mode!="Echo") {
if(m_monitoring or m_transmitting) { if(m_monitoring or m_transmitting) {
@ -4890,8 +4850,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
return; return;
} }
if ((message.isJT9 () and m_modeTx != "JT9" and m_mode != "JT4") or if ((message.isJT9 () and m_mode != "JT9" and m_mode != "JT4") or
(message.isJT65 () and m_modeTx != "JT65" and m_mode != "JT4")) { (message.isJT65 () and m_mode != "JT65" and m_mode != "JT4")) {
// We are not allowing mode change, so don't process decode // We are not allowing mode change, so don't process decode
return; return;
} }
@ -5279,27 +5239,32 @@ void MainWindow::setTxMsg(int n)
void MainWindow::genCQMsg () void MainWindow::genCQMsg ()
{ {
if(m_config.my_callsign().size () && m_config.my_grid().size ()) { auto const& my_callsign = m_config.my_callsign ();
QString grid{m_config.my_grid()}; auto is_compound = my_callsign != m_baseCall;
auto is_type_two = !is77BitMode () && is_compound && stdCall (m_baseCall) && !shortList (my_callsign);
if(my_callsign.size () && m_config.my_grid().size ()) {
auto const& grid = m_config.my_grid ();
if (ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked ()) { if (ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked ()) {
if(stdCall(m_config.my_callsign())) { if(stdCall (my_callsign)
|| is_type_two) {
msgtype (QString {"CQ %1 %2 %3"} msgtype (QString {"CQ %1 %2 %3"}
.arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'}) .arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'})
.arg (m_config.my_callsign()) .arg (my_callsign)
.arg (grid.left (4)), .arg (grid.left (4)),
ui->tx6); ui->tx6);
} else { } else {
msgtype (QString {"CQ %1 %2"} msgtype (QString {"CQ %1 %2"}
.arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'}) .arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'})
.arg (m_config.my_callsign()), .arg (my_callsign),
ui->tx6); ui->tx6);
} }
} else { } else {
if(stdCall(m_config.my_callsign())) { if (stdCall (my_callsign)
msgtype (QString {"%1 %2 %3"}.arg(m_CQtype).arg(m_config.my_callsign()) || is_type_two) {
msgtype (QString {"%1 %2 %3"}.arg(m_CQtype).arg(my_callsign)
.arg(grid.left(4)),ui->tx6); .arg(grid.left(4)),ui->tx6);
} else { } else {
msgtype (QString {"%1 %2"}.arg(m_CQtype).arg(m_config.my_callsign()),ui->tx6); msgtype (QString {"%1 %2"}.arg(m_CQtype).arg(my_callsign),ui->tx6);
} }
} }
if ((m_mode=="JT4" or m_mode=="Q65") and ui->cbShMsgs->isChecked()) { if ((m_mode=="JT4" or m_mode=="Q65") and ui->cbShMsgs->isChecked()) {
@ -5314,15 +5279,15 @@ void MainWindow::genCQMsg ()
QStringList tlist=t.split(" "); QStringList tlist=t.split(" ");
if((m_mode=="FT4" or m_mode=="FT8" or m_mode=="MSK144") and if((m_mode=="FT4" or m_mode=="FT8" or m_mode=="MSK144") and
SpecOp::NONE != m_config.special_op_id() and SpecOp::NONE != m_config.special_op_id() and
( tlist.at(1)==m_config.my_callsign() or ( tlist.at(1)==my_callsign or
tlist.at(2)==m_config.my_callsign() ) and tlist.at(2)==my_callsign ) and
stdCall(m_config.my_callsign())) { stdCall(my_callsign)) {
if(SpecOp::NA_VHF == m_config.special_op_id()) m_cqStr="TEST"; if(SpecOp::NA_VHF == m_config.special_op_id()) m_cqStr="TEST";
if(SpecOp::EU_VHF == m_config.special_op_id()) m_cqStr="TEST"; if(SpecOp::EU_VHF == m_config.special_op_id()) m_cqStr="TEST";
if(SpecOp::FIELD_DAY == m_config.special_op_id()) m_cqStr="FD"; if(SpecOp::FIELD_DAY == m_config.special_op_id()) m_cqStr="FD";
if(SpecOp::RTTY == m_config.special_op_id()) m_cqStr="RU"; if(SpecOp::RTTY == m_config.special_op_id()) m_cqStr="RU";
if(SpecOp::WW_DIGI == m_config.special_op_id()) m_cqStr="WW"; if(SpecOp::WW_DIGI == m_config.special_op_id()) m_cqStr="WW";
if( tlist.at(1)==m_config.my_callsign() ) { if( tlist.at(1)==my_callsign ) {
t="CQ " + m_cqStr + " " + tlist.at(1) + " " + tlist.at(2); t="CQ " + m_cqStr + " " + tlist.at(1) + " " + tlist.at(2);
} else { } else {
t="CQ " + m_cqStr + " " + tlist.at(2) + " " + tlist.at(3); t="CQ " + m_cqStr + " " + tlist.at(2) + " " + tlist.at(3);
@ -5355,6 +5320,12 @@ bool MainWindow::stdCall(QString const& w)
return standard_call_re.match (w).hasMatch (); return standard_call_re.match (w).hasMatch ();
} }
bool MainWindow::is77BitMode () const
{
return "FT8" == m_mode || "FT4" == m_mode || "MSK144" == m_mode
|| "FST4" == m_mode || "Q65" == m_mode;
}
void MainWindow::genStdMsgs(QString rpt, bool unconditional) void MainWindow::genStdMsgs(QString rpt, bool unconditional)
{ {
genCQMsg (); genCQMsg ();
@ -5371,7 +5342,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
} }
auto const& my_callsign = m_config.my_callsign (); auto const& my_callsign = m_config.my_callsign ();
auto is_compound = my_callsign != m_baseCall; auto is_compound = my_callsign != m_baseCall;
auto is_type_one = is_compound && shortList (my_callsign); auto is_type_one = !is77BitMode () && is_compound && shortList (my_callsign);
auto const& my_grid = m_config.my_grid ().left (4); auto const& my_grid = m_config.my_grid ().left (4);
auto const& hisBase = Radio::base_callsign (hisCall); auto const& hisBase = Radio::base_callsign (hisCall);
auto eme_short_codes = m_config.enable_VHF_features () && ui->cbShMsgs->isChecked () auto eme_short_codes = m_config.enable_VHF_features () && ui->cbShMsgs->isChecked ()
@ -5384,7 +5355,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
QString t0s=hisCall + " " + my_callsign + " "; QString t0s=hisCall + " " + my_callsign + " ";
QString t0a,t0b; QString t0a,t0b;
if(bHisCall and bMyCall) t0=hisCall + " " + my_callsign + " "; if (is77BitMode () && bHisCall && bMyCall) t0=hisCall + " " + my_callsign + " ";
t0a="<"+hisCall + "> " + my_callsign + " "; t0a="<"+hisCall + "> " + my_callsign + " ";
t0b=hisCall + " <" + my_callsign + "> "; t0b=hisCall + " <" + my_callsign + "> ";
@ -5402,7 +5373,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
int n=rpt.toInt(); int n=rpt.toInt();
rpt = rpt.asprintf("%+2.2d",n); rpt = rpt.asprintf("%+2.2d",n);
if(m_mode=="MSK144" or m_mode=="FT8" or m_mode=="FT4" || m_mode=="FST4") { if (is77BitMode ()) {
QString t2,t3; QString t2,t3;
QString sent=rpt; QString sent=rpt;
QString rs,rst; QString rs,rst;
@ -5466,8 +5437,8 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
} }
} }
if((m_mode!="MSK144" and m_mode!="FT8" and m_mode!="FT4" && m_mode != "FST4")) { if (!is77BitMode ()) {
t=t00 + rpt; t=(is_type_one ? t0 : t00) + rpt;
msgtype(t, ui->tx2); msgtype(t, ui->tx2);
t=t0 + "R" + rpt; t=t0 + "R" + rpt;
msgtype(t, ui->tx3); msgtype(t, ui->tx3);
@ -5506,7 +5477,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
} }
} }
if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="MSK144" || m_mode == "FST4") return; if (is77BitMode ()) return;
if (is_compound) { if (is_compound) {
if (is_type_one) { if (is_type_one) {
@ -5519,8 +5490,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
case Configuration::type_2_msg_1_full: case Configuration::type_2_msg_1_full:
msgtype(t + my_grid, ui->tx1); msgtype(t + my_grid, ui->tx1);
if (!eme_short_codes) { if (!eme_short_codes) {
if((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4" || m_mode == "FST4") && if(is77BitMode () && SpecOp::NA_VHF == m_config.special_op_id()) {
SpecOp::NA_VHF == m_config.special_op_id()) {
msgtype(t + "R " + my_grid, ui->tx3); // #### Unreachable code msgtype(t + "R " + my_grid, ui->tx3); // #### Unreachable code
} else { } else {
msgtype(t + "R" + rpt, ui->tx3); msgtype(t + "R" + rpt, ui->tx3);
@ -5532,8 +5502,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
break; break;
case Configuration::type_2_msg_3_full: case Configuration::type_2_msg_3_full:
if ((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4" || m_mode == "FST4") && if (is77BitMode () && SpecOp::NA_VHF == m_config.special_op_id()) {
SpecOp::NA_VHF == m_config.special_op_id()) {
msgtype(t + "R " + my_grid, ui->tx3); msgtype(t + "R " + my_grid, ui->tx3);
msgtype(t + "RRR", ui->tx4); msgtype(t + "RRR", ui->tx4);
} else { } else {
@ -5548,8 +5517,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
case Configuration::type_2_msg_5_only: case Configuration::type_2_msg_5_only:
msgtype(t00 + my_grid, ui->tx1); msgtype(t00 + my_grid, ui->tx1);
if (!eme_short_codes) { if (!eme_short_codes) {
if ((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4" || m_mode == "FST4") && if (is77BitMode () && SpecOp::NA_VHF == m_config.special_op_id()) {
SpecOp::NA_VHF == m_config.special_op_id()) {
msgtype(t + "R " + my_grid, ui->tx3); // #### Unreachable code msgtype(t + "R " + my_grid, ui->tx3); // #### Unreachable code
msgtype(t + "RRR", ui->tx4); msgtype(t + "RRR", ui->tx4);
} else { } else {
@ -5584,7 +5552,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional)
} }
} }
m_rpt=rpt; m_rpt=rpt;
if(SpecOp::HOUND == m_config.special_op_id() and is_compound) ui->tx1->setText("DE " + m_config.my_callsign()); if(SpecOp::HOUND == m_config.special_op_id() and is_compound) ui->tx1->setText("DE " + my_callsign);
} }
void MainWindow::TxAgain() void MainWindow::TxAgain()
@ -5948,7 +5916,7 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button
default: break; default: break;
} }
m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd, m_logDlg->initLogQSO (m_hisCall, grid, m_mode, m_rptSent, m_rptRcvd,
m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal +
ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd); ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd);
m_inQSOwith=""; m_inQSOwith="";
@ -6087,7 +6055,7 @@ void MainWindow::displayWidgets(qint64 n)
void MainWindow::on_actionFST4_triggered() void MainWindow::on_actionFST4_triggered()
{ {
m_mode="FST4"; m_mode="FST4";
m_modeTx="FST4"; m_mode="FST4";
ui->actionFST4->setChecked(true); ui->actionFST4->setChecked(true);
m_bFast9=false; m_bFast9=false;
m_bFastMode=false; m_bFastMode=false;
@ -6111,7 +6079,6 @@ void MainWindow::on_actionFST4_triggered()
setup_status_bar(false); setup_status_bar(false);
ui->cbAutoSeq->setChecked(true); ui->cbAutoSeq->setChecked(true);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
m_wideGraph->setPeriod(m_TRperiod,6912); m_wideGraph->setPeriod(m_TRperiod,6912);
m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value());
m_wideGraph->setTol(ui->sbFtol->value()); m_wideGraph->setTol(ui->sbFtol->value());
@ -6130,7 +6097,6 @@ void MainWindow::on_actionFST4_triggered()
void MainWindow::on_actionFST4W_triggered() void MainWindow::on_actionFST4W_triggered()
{ {
m_mode="FST4W"; m_mode="FST4W";
m_modeTx="FST4W";
ui->actionFST4W->setChecked(true); ui->actionFST4W->setChecked(true);
m_bFast9=false; m_bFast9=false;
m_bFastMode=false; m_bFastMode=false;
@ -6149,7 +6115,6 @@ void MainWindow::on_actionFST4W_triggered()
ui->WSPRfreqSpinBox->setMinimum(100); ui->WSPRfreqSpinBox->setMinimum(100);
ui->WSPRfreqSpinBox->setMaximum(5000); ui->WSPRfreqSpinBox->setMaximum(5000);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
m_wideGraph->setPeriod(m_TRperiod,6912); m_wideGraph->setPeriod(m_TRperiod,6912);
m_wideGraph->setTxFreq(ui->WSPRfreqSpinBox->value()); m_wideGraph->setTxFreq(ui->WSPRfreqSpinBox->value());
m_wideGraph->setRxFreq(ui->sbFST4W_RxFreq->value()); m_wideGraph->setRxFreq(ui->sbFST4W_RxFreq->value());
@ -6162,7 +6127,6 @@ void MainWindow::on_actionFST4W_triggered()
void MainWindow::on_actionFT4_triggered() void MainWindow::on_actionFT4_triggered()
{ {
m_mode="FT4"; m_mode="FT4";
m_modeTx="FT4";
m_TRperiod=7.5; m_TRperiod=7.5;
bool bVHF=m_config.enable_VHF_features(); bool bVHF=m_config.enable_VHF_features();
m_bFast9=false; m_bFast9=false;
@ -6177,7 +6141,6 @@ void MainWindow::on_actionFT4_triggered()
m_toneSpacing=12000.0/576.0; m_toneSpacing=12000.0/576.0;
ui->actionFT4->setChecked(true); ui->actionFT4->setChecked(true);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
m_send_RR73=true; m_send_RR73=true;
VHF_features_enabled(bVHF); VHF_features_enabled(bVHF);
m_fastGraph->hide(); m_fastGraph->hide();
@ -6212,7 +6175,6 @@ void MainWindow::on_actionFT8_triggered()
m_bFastMode=false; m_bFastMode=false;
WSPR_config(false); WSPR_config(false);
switch_mode (Modes::FT8); switch_mode (Modes::FT8);
m_modeTx="FT8";
m_nsps=6912; m_nsps=6912;
m_FFTSize = m_nsps / 2; m_FFTSize = m_nsps / 2;
Q_EMIT FFTSize (m_FFTSize); Q_EMIT FFTSize (m_FFTSize);
@ -6221,7 +6183,6 @@ void MainWindow::on_actionFT8_triggered()
m_toneSpacing=0.0; //??? m_toneSpacing=0.0; //???
ui->actionFT8->setChecked(true); //??? ui->actionFT8->setChecked(true); //???
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
VHF_features_enabled(bVHF); VHF_features_enabled(bVHF);
ui->cbAutoSeq->setChecked(true); ui->cbAutoSeq->setChecked(true);
m_TRperiod=15.0; m_TRperiod=15.0;
@ -6316,7 +6277,6 @@ void MainWindow::on_actionJT4_triggered()
bool bVHF=m_config.enable_VHF_features(); bool bVHF=m_config.enable_VHF_features();
WSPR_config(false); WSPR_config(false);
switch_mode (Modes::JT4); switch_mode (Modes::JT4);
m_modeTx="JT4";
m_TRperiod=60.0; m_TRperiod=60.0;
m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe
m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe
@ -6330,7 +6290,6 @@ void MainWindow::on_actionJT4_triggered()
VHF_features_enabled(true); VHF_features_enabled(true);
m_wideGraph->setPeriod(m_TRperiod,m_nsps); m_wideGraph->setPeriod(m_TRperiod,m_nsps);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
m_bFastMode=false; m_bFastMode=false;
m_bFast9=false; m_bFast9=false;
setup_status_bar (bVHF); setup_status_bar (bVHF);
@ -6362,7 +6321,6 @@ void MainWindow::on_actionJT9_triggered()
m_bFastMode=m_bFast9; m_bFastMode=m_bFast9;
WSPR_config(false); WSPR_config(false);
switch_mode (Modes::JT9); switch_mode (Modes::JT9);
m_modeTx="JT9";
m_nsps=6912; m_nsps=6912;
m_FFTSize = m_nsps / 2; m_FFTSize = m_nsps / 2;
Q_EMIT FFTSize (m_FFTSize); Q_EMIT FFTSize (m_FFTSize);
@ -6372,7 +6330,6 @@ void MainWindow::on_actionJT9_triggered()
m_toneSpacing=0.0; m_toneSpacing=0.0;
ui->actionJT9->setChecked(true); ui->actionJT9->setChecked(true);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
VHF_features_enabled(bVHF); VHF_features_enabled(bVHF);
if(m_nSubMode>=4 and bVHF) { if(m_nSubMode>=4 and bVHF) {
ui->cbFast9->setEnabled(true); ui->cbFast9->setEnabled(true);
@ -6419,7 +6376,6 @@ void MainWindow::on_actionJT65_triggered()
{ {
on_actionJT9_triggered(); on_actionJT9_triggered();
m_mode="JT65"; m_mode="JT65";
m_modeTx="JT65";
bool bVHF=m_config.enable_VHF_features(); bool bVHF=m_config.enable_VHF_features();
WSPR_config(false); WSPR_config(false);
switch_mode (Modes::JT65); switch_mode (Modes::JT65);
@ -6436,7 +6392,6 @@ void MainWindow::on_actionJT65_triggered()
VHF_features_enabled(bVHF); VHF_features_enabled(bVHF);
m_wideGraph->setPeriod(m_TRperiod,m_nsps); m_wideGraph->setPeriod(m_TRperiod,m_nsps);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value());
m_wideGraph->setTol(ui->sbFtol->value()); m_wideGraph->setTol(ui->sbFtol->value());
m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value());
@ -6470,12 +6425,12 @@ void MainWindow::on_actionJT65_triggered()
void MainWindow::on_actionQ65_triggered() void MainWindow::on_actionQ65_triggered()
{ {
m_mode="Q65"; m_mode="Q65";
m_modeTx="Q65";
ui->actionQ65->setChecked(true); ui->actionQ65->setChecked(true);
switch_mode(Modes::Q65); switch_mode(Modes::Q65);
fast_config(false); fast_config(false);
WSPR_config(false); WSPR_config(false);
setup_status_bar(true); setup_status_bar(true);
ui->actionQuickDecode->setChecked(true);
m_nsps=6912; //For symspec only m_nsps=6912; //For symspec only
m_FFTSize = m_nsps / 2; m_FFTSize = m_nsps / 2;
Q_EMIT FFTSize(m_FFTSize); Q_EMIT FFTSize(m_FFTSize);
@ -6486,7 +6441,6 @@ void MainWindow::on_actionQ65_triggered()
QString fname {QDir::toNativeSeparators(m_config.temp_dir().absoluteFilePath ("red.dat"))}; QString fname {QDir::toNativeSeparators(m_config.temp_dir().absoluteFilePath ("red.dat"))};
m_wideGraph->setRedFile(fname); m_wideGraph->setRedFile(fname);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
m_wideGraph->setPeriod(m_TRperiod,6912); m_wideGraph->setPeriod(m_TRperiod,6912);
m_wideGraph->setTol(ui->sbFtol->value()); m_wideGraph->setTol(ui->sbFtol->value());
m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value());
@ -6530,7 +6484,6 @@ void MainWindow::on_actionMSK144_triggered()
return; return;
} }
m_mode="MSK144"; m_mode="MSK144";
m_modeTx="MSK144";
ui->actionMSK144->setChecked(true); ui->actionMSK144->setChecked(true);
switch_mode (Modes::MSK144); switch_mode (Modes::MSK144);
m_nsps=6; m_nsps=6;
@ -6586,7 +6539,6 @@ void MainWindow::on_actionWSPR_triggered()
m_mode="WSPR"; m_mode="WSPR";
WSPR_config(true); WSPR_config(true);
switch_mode (Modes::WSPR); switch_mode (Modes::WSPR);
m_modeTx="WSPR";
m_TRperiod=120.0; m_TRperiod=120.0;
m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe
m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe
@ -6602,7 +6554,6 @@ void MainWindow::on_actionWSPR_triggered()
ui->WSPRfreqSpinBox->setMaximum(1600); ui->WSPRfreqSpinBox->setMaximum(1600);
m_wideGraph->setPeriod(m_TRperiod,m_nsps); m_wideGraph->setPeriod(m_TRperiod,m_nsps);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
m_bFastMode=false; m_bFastMode=false;
m_bFast9=false; m_bFast9=false;
ui->TxFreqSpinBox->setValue(ui->WSPRfreqSpinBox->value()); ui->TxFreqSpinBox->setValue(ui->WSPRfreqSpinBox->value());
@ -6626,10 +6577,8 @@ void MainWindow::on_actionEcho_triggered()
m_hsymStop=9; m_hsymStop=9;
m_toneSpacing=1.0; m_toneSpacing=1.0;
switch_mode(Modes::Echo); switch_mode(Modes::Echo);
m_modeTx="Echo";
setup_status_bar (true); setup_status_bar (true);
m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
ui->TxFreqSpinBox->setValue(1500); ui->TxFreqSpinBox->setValue(1500);
ui->TxFreqSpinBox->setEnabled (false); ui->TxFreqSpinBox->setEnabled (false);
if(!m_echoGraph->isVisible()) m_echoGraph->show(); if(!m_echoGraph->isVisible()) m_echoGraph->show();
@ -7315,7 +7264,7 @@ void MainWindow::rigFailure (QString const& reason)
void MainWindow::transmit (double snr) void MainWindow::transmit (double snr)
{ {
double toneSpacing=0.0; double toneSpacing=0.0;
if (m_modeTx == "JT65") { if (m_mode == "JT65") {
if(m_nSubMode==0) toneSpacing=11025.0/4096.0; if(m_nSubMode==0) toneSpacing=11025.0/4096.0;
if(m_nSubMode==1) toneSpacing=2*11025.0/4096.0; if(m_nSubMode==1) toneSpacing=2*11025.0/4096.0;
if(m_nSubMode==2) toneSpacing=4*11025.0/4096.0; if(m_nSubMode==2) toneSpacing=4*11025.0/4096.0;
@ -7325,7 +7274,7 @@ void MainWindow::transmit (double snr)
true, false, snr, m_TRperiod); true, false, snr, m_TRperiod);
} }
if (m_modeTx == "FT8") { if (m_mode == "FT8") {
// toneSpacing=12000.0/1920.0; // toneSpacing=12000.0/1920.0;
toneSpacing=-3; toneSpacing=-3;
if(m_config.x2ToneSpacing()) toneSpacing=2*12000.0/1920.0; if(m_config.x2ToneSpacing()) toneSpacing=2*12000.0/1920.0;
@ -7337,7 +7286,7 @@ void MainWindow::transmit (double snr)
true, false, snr, m_TRperiod); true, false, snr, m_TRperiod);
} }
if (m_modeTx == "FT4") { if (m_mode == "FT4") {
m_dateTimeSentTx3=QDateTime::currentDateTimeUtc(); m_dateTimeSentTx3=QDateTime::currentDateTimeUtc();
toneSpacing=-2.0; //Transmit a pre-computed, filtered waveform. toneSpacing=-2.0; //Transmit a pre-computed, filtered waveform.
Q_EMIT sendMessage (m_mode, NUM_FT4_SYMBOLS, Q_EMIT sendMessage (m_mode, NUM_FT4_SYMBOLS,
@ -7346,7 +7295,7 @@ void MainWindow::transmit (double snr)
true, false, snr, m_TRperiod); true, false, snr, m_TRperiod);
} }
if (m_modeTx == "FST4" or m_modeTx == "FST4W") { if (m_mode == "FST4" or m_mode == "FST4W") {
m_dateTimeSentTx3=QDateTime::currentDateTimeUtc(); m_dateTimeSentTx3=QDateTime::currentDateTimeUtc();
toneSpacing=-2.0; //Transmit a pre-computed, filtered waveform. toneSpacing=-2.0; //Transmit a pre-computed, filtered waveform.
int nsps=720; int nsps=720;
@ -7368,7 +7317,7 @@ void MainWindow::transmit (double snr)
true, false, snr, m_TRperiod); true, false, snr, m_TRperiod);
} }
if (m_modeTx == "Q65") { if (m_mode == "Q65") {
int nsps=1800; int nsps=1800;
if(m_TRperiod==30) nsps=3600; if(m_TRperiod==30) nsps=3600;
if(m_TRperiod==60) nsps=7200; if(m_TRperiod==60) nsps=7200;
@ -7383,7 +7332,7 @@ void MainWindow::transmit (double snr)
true, false, snr, m_TRperiod); true, false, snr, m_TRperiod);
} }
if (m_modeTx == "JT9") { if (m_mode == "JT9") {
int nsub=pow(2,m_nSubMode); int nsub=pow(2,m_nSubMode);
int nsps[]={480,240,120,60}; int nsps[]={480,240,120,60};
double sps=m_nsps; double sps=m_nsps;
@ -7402,7 +7351,7 @@ void MainWindow::transmit (double snr)
true, fastmode, snr, m_TRperiod); true, fastmode, snr, m_TRperiod);
} }
if (m_modeTx == "MSK144") { if (m_mode == "MSK144") {
m_nsps=6; m_nsps=6;
double f0=1000.0; double f0=1000.0;
if(!m_bFastMode) { if(!m_bFastMode) {
@ -7420,7 +7369,7 @@ void MainWindow::transmit (double snr)
true, true, snr, m_TRperiod); true, true, snr, m_TRperiod);
} }
if (m_modeTx == "JT4") { if (m_mode == "JT4") {
if(m_nSubMode==0) toneSpacing=4.375; if(m_nSubMode==0) toneSpacing=4.375;
if(m_nSubMode==1) toneSpacing=2*4.375; if(m_nSubMode==1) toneSpacing=2*4.375;
if(m_nSubMode==2) toneSpacing=4*4.375; if(m_nSubMode==2) toneSpacing=4*4.375;
@ -7599,7 +7548,7 @@ void::MainWindow::VHF_features_enabled(bool b)
} }
ui->actionInclude_averaging->setVisible (b); ui->actionInclude_averaging->setVisible (b);
ui->actionInclude_correlation->setVisible (b && m_mode!="Q65"); ui->actionInclude_correlation->setVisible (b && m_mode!="Q65");
ui->actionMessage_averaging->setEnabled(b); ui->actionMessage_averaging->setEnabled(b && (m_mode=="JT4" or m_mode=="JT65"));
ui->actionEnable_AP_JT65->setVisible (b && m_mode=="JT65"); ui->actionEnable_AP_JT65->setVisible (b && m_mode=="JT65");
if(!b && m_msgAvgWidget and (SpecOp::FOX != m_config.special_op_id()) and !m_config.autoLog()) { if(!b && m_msgAvgWidget and (SpecOp::FOX != m_config.special_op_id()) and !m_config.autoLog()) {
@ -8423,7 +8372,7 @@ void MainWindow::statusUpdate () const
} }
m_messageClient->status_update (m_freqNominal, m_mode, m_hisCall, m_messageClient->status_update (m_freqNominal, m_mode, m_hisCall,
QString::number (ui->rptSpinBox->value ()), QString::number (ui->rptSpinBox->value ()),
m_modeTx, ui->autoButton->isChecked (), m_mode, ui->autoButton->isChecked (),
m_transmitting, m_decoderBusy, m_transmitting, m_decoderBusy,
rx_frequency, ui->TxFreqSpinBox->value (), rx_frequency, ui->TxFreqSpinBox->value (),
m_config.my_callsign (), m_config.my_grid (), m_config.my_callsign (), m_config.my_grid (),
@ -8556,7 +8505,7 @@ void MainWindow::write_transmit_entry (QString const& file_name)
time = time.addSecs (-fmod(double(time.time().second()),m_TRperiod)); time = time.addSecs (-fmod(double(time.time().second()),m_TRperiod));
out << time.toString("yyMMdd_hhmmss") out << time.toString("yyMMdd_hhmmss")
<< " Transmitting " << qSetRealNumberPrecision (12) << (m_freqNominal / 1.e6) << " Transmitting " << qSetRealNumberPrecision (12) << (m_freqNominal / 1.e6)
<< " MHz " << m_modeTx << " MHz " << m_mode
<< ": " << m_currentMessage << ": " << m_currentMessage
#if QT_VERSION >= QT_VERSION_CHECK (5, 15, 0) #if QT_VERSION >= QT_VERSION_CHECK (5, 15, 0)
<< Qt::endl << Qt::endl

View File

@ -419,7 +419,6 @@ private:
Astro::Correction m_astroCorrection; Astro::Correction m_astroCorrection;
bool m_reverse_Doppler; bool m_reverse_Doppler;
double m_s6;
double m_tRemaining; double m_tRemaining;
double m_TRperiod; double m_TRperiod;
@ -454,7 +453,6 @@ private:
qint32 m_nclearave; qint32 m_nclearave;
qint32 m_minSync; qint32 m_minSync;
qint32 m_dBm; qint32 m_dBm;
qint32 m_nseq;
qint32 m_nWSPRdecodes; qint32 m_nWSPRdecodes;
qint32 m_k0; qint32 m_k0;
qint32 m_kdone; qint32 m_kdone;
@ -612,7 +610,6 @@ private:
QString m_palette; QString m_palette;
QString m_dateTime; QString m_dateTime;
QString m_mode; QString m_mode;
QString m_modeTx;
QString m_fnameWE; // save path without extension QString m_fnameWE; // save path without extension
QString m_rpt; QString m_rpt;
QString m_nextRpt; QString m_nextRpt;
@ -781,6 +778,7 @@ private:
void foxGenWaveform(int i,QString fm); void foxGenWaveform(int i,QString fm);
void writeFoxQSO (QString const& msg); void writeFoxQSO (QString const& msg);
void to_jt9(qint32 n, qint32 istart, qint32 idone); void to_jt9(qint32 n, qint32 istart, qint32 idone);
bool is77BitMode () const;
}; };
extern int killbyname(const char* progName); extern int killbyname(const char* progName);

View File

@ -644,7 +644,7 @@ QPushButton[state=&quot;ok&quot;] {
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QComboBox" name="bandComboBox"> <widget class="BandComboBox" name="bandComboBox">
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select operating band or enter frequency in MHz or enter kHz increment followed by k.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Select operating band or enter frequency in MHz or enter kHz increment followed by k.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
@ -661,7 +661,7 @@ QPushButton[state=&quot;ok&quot;] {
<enum>QComboBox::NoInsert</enum> <enum>QComboBox::NoInsert</enum>
</property> </property>
<property name="sizeAdjustPolicy"> <property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToMinimumContentsLength</enum> <enum>QComboBox::AdjustToMinimumContentsLengthWithIcon</enum>
</property> </property>
</widget> </widget>
</item> </item>
@ -3434,7 +3434,7 @@ Double-click to reset to the standard 73 message</string>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
<class>DisplayText</class> <class>DisplayText</class>
<extends>QTextEdit</extends> <extends>QTextBrowser</extends>
<header>widgets/displaytext.h</header> <header>widgets/displaytext.h</header>
</customwidget> </customwidget>
<customwidget> <customwidget>
@ -3468,6 +3468,11 @@ Double-click to reset to the standard 73 message</string>
<extends>QPushButton</extends> <extends>QPushButton</extends>
<header>widgets/DoubleClickablePushButton.hpp</header> <header>widgets/DoubleClickablePushButton.hpp</header>
</customwidget> </customwidget>
<customwidget>
<class>BandComboBox</class>
<extends>QComboBox</extends>
<header>widgets/BandComboBox.hpp</header>
</customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>decodedTextBrowser</tabstop> <tabstop>decodedTextBrowser</tabstop>

View File

@ -479,7 +479,7 @@ void CPlotter::DrawOverlay() //DrawOverlay()
} }
} }
if(m_modeTx=="JT9" and m_nSubMode>0) { //JT9 if(m_mode=="JT9" and m_nSubMode>0) { //JT9
bw=8.0*12000.0/m_nsps; bw=8.0*12000.0/m_nsps;
if(m_nSubMode==1) bw=2*bw; //B if(m_nSubMode==1) bw=2*bw; //B
if(m_nSubMode==2) bw=4*bw; //C if(m_nSubMode==2) bw=4*bw; //C
@ -500,7 +500,7 @@ void CPlotter::DrawOverlay() //DrawOverlay()
float baud=12000.0/nsps; float baud=12000.0/nsps;
bw=65.0*h*baud; bw=65.0*h*baud;
} }
if(m_modeTx=="JT65") { //JT65 if(m_mode=="JT65") { //JT65
bw=65.0*11025.0/4096.0; bw=65.0*11025.0/4096.0;
if(m_nSubMode==1) bw=2*bw; //B if(m_nSubMode==1) bw=2*bw; //B
if(m_nSubMode==2) bw=4*bw; //C if(m_nSubMode==2) bw=4*bw; //C
@ -817,11 +817,6 @@ void CPlotter::setSubMode(int n) //setSubMode
m_nSubMode=n; m_nSubMode=n;
} }
void CPlotter::setModeTx(QString modeTx) //setModeTx
{
m_modeTx=modeTx;
}
int CPlotter::Fmax() int CPlotter::Fmax()
{ {
return m_fMax; return m_fMax;

View File

@ -61,7 +61,6 @@ public:
void setTxFreq(int n); void setTxFreq(int n);
void setMode(QString mode); void setMode(QString mode);
void setSubMode(int n); void setSubMode(int n);
void setModeTx(QString modeTx);
void SetPercent2DScreen(int percent); void SetPercent2DScreen(int percent);
int Fmax(); int Fmax();
void setDialFreq(double d); void setDialFreq(double d);
@ -149,7 +148,6 @@ private:
QString m_HDivText[483]; QString m_HDivText[483];
QString m_mode; QString m_mode;
QString m_mode0; QString m_mode0;
QString m_modeTx;
QString m_rxBand; QString m_rxBand;
QString m_redFile; QString m_redFile;

View File

@ -305,13 +305,6 @@ void WideGraph::setSubMode(int n) //setSubMode
ui->widePlot->DrawOverlay(); ui->widePlot->DrawOverlay();
ui->widePlot->update(); ui->widePlot->update();
} }
void WideGraph::setModeTx(QString modeTx) //setModeTx
{
m_modeTx=modeTx;
ui->widePlot->setModeTx(modeTx);
ui->widePlot->DrawOverlay();
ui->widePlot->update();
}
void WideGraph::on_spec2dComboBox_currentIndexChanged(int index) void WideGraph::on_spec2dComboBox_currentIndexChanged(int index)
{ {

View File

@ -39,7 +39,6 @@ public:
void setTxFreq(int n); void setTxFreq(int n);
void setMode(QString mode); void setMode(QString mode);
void setSubMode(int n); void setSubMode(int n);
void setModeTx(QString modeTx);
bool flatten(); bool flatten();
bool useRef(); bool useRef();
void setTol(int n); void setTol(int n);
@ -116,7 +115,6 @@ private:
QString m_rxBand; QString m_rxBand;
QString m_mode; QString m_mode;
QString m_modeTx;
QString m_waterfallPalette; QString m_waterfallPalette;
float m_swide[MAX_SCREENSIZE]; float m_swide[MAX_SCREENSIZE];
QString m_user_defined; QString m_user_defined;

View File

@ -65,6 +65,7 @@ SOURCES += \
getfile.cpp \ getfile.cpp \
WFPalette.cpp \ WFPalette.cpp \
WsprTxScheduler.cpp \ WsprTxScheduler.cpp \
helper_functions.cpp \
main.cpp decodedtext.cpp wsprnet.cpp \ main.cpp decodedtext.cpp wsprnet.cpp \
WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\ WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\
MultiSettings.cpp PhaseEqualizationDialog.cpp \ MultiSettings.cpp PhaseEqualizationDialog.cpp \
@ -72,6 +73,7 @@ SOURCES += \
LotWUsers.cpp TraceFile.cpp LotWUsers.cpp TraceFile.cpp
HEADERS += qt_helpers.hpp qt_db_helpers.hpp \ HEADERS += qt_helpers.hpp qt_db_helpers.hpp \
helper_functions.h \
pimpl_h.hpp pimpl_impl.hpp \ pimpl_h.hpp pimpl_impl.hpp \
ExceptionCatchingApplication.hpp Logger.hpp WSJTXLogging.hpp \ ExceptionCatchingApplication.hpp Logger.hpp WSJTXLogging.hpp \
Radio.hpp NetworkServerLookup.hpp revision_utils.hpp \ Radio.hpp NetworkServerLookup.hpp revision_utils.hpp \