WSJT-X/mainwindow.cpp
Bill Somerville c05689944a Bugfixes:
Detector no longer collects samples when transmitting or not
monitoring. This was causingissues with the waterfall after tx periods
and was a waste of CPU cycles.

Correct the missing window title on the waterfall window.

Stop and restart the output audio stream if the configuration of
device or channels changes in the setup dialog. This defect was
causing spurious transmissions after changing configuration.



git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@3543 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
2013-08-11 01:30:05 +00:00

3095 lines
93 KiB
C++

//--------------------------------------------------------------- MainWindow
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <QColorDialog>
#include "soundout.h"
#include "devsetup.h"
#include "plotter.h"
#include "about.h"
#include "widegraph.h"
#include "sleep.h"
#include "getfile.h"
#include "logqso.h"
#ifdef QT5
#include <QtConcurrent/QtConcurrentRun>
#endif
int itone[NUM_JT65_SYMBOLS]; //Audio tones for all Tx symbols
int icw[NUM_CW_SYMBOLS]; //Dits for CW ID
int outBufSize;
int rc;
qint32 g_COMportOpen;
qint32 g_iptt;
static int nc1=1;
wchar_t buffer[256];
Rig* rig = NULL;
QTextEdit* pShortcuts;
QTcpSocket* commanderSocket = new QTcpSocket(0);
QString rev="$Rev$";
QString Program_Title_Version=" WSJT-X v1.2, r" + rev.mid(6,4) +
" by K1JT";
//-------------------------------------------------- MainWindow constructor
// Multiple instances: new arg *thekey
MainWindow::MainWindow(QSettings * settings, QSharedMemory *shdmem, QString *thekey,
qint32 fontSize2, qint32 fontWeight2,
QWidget *parent) :
QMainWindow(parent),
m_settings (settings),
ui(new Ui::MainWindow),
m_wideGraph (new WideGraph (settings)),
m_logDlg (new LogQSO (settings, this)),
m_detector (RX_SAMPLE_RATE, NTMAX / 2, 6912 / 2, this),
m_audioInputDevice (QAudioDeviceInfo::defaultInputDevice ()), // start with default
m_modulator (TX_SAMPLE_RATE, NTMAX / 2),
m_audioOutputDevice (QAudioDeviceInfo::defaultOutputDevice ()), // start with default
m_soundOutput (&m_modulator)
{
ui->setupUi(this);
connect (this, &MainWindow::finished, this, &MainWindow::close);
// start sound out thread and hook up slots & signals for shutdown management
// these two objects need to be in the other thread so that invoking
// their slots is done in a thread safe way
m_soundOutput.moveToThread (&m_soundOutputThread);
m_modulator.moveToThread (&m_soundOutputThread);
connect (this, &MainWindow::finished, &m_soundOutputThread, &QThread::quit); // quit thread event loop
connect (&m_soundOutputThread, &QThread::finished, &m_soundOutputThread, &QThread::deleteLater); // disposal
// hook up sound output stream slots & signals
connect (this, SIGNAL (startAudioOutputStream (QAudioDeviceInfo const&, unsigned)), &m_soundOutput, SLOT (startStream (QAudioDeviceInfo const&, unsigned)));
connect (this, SIGNAL (stopAudioOutputStream ()), &m_soundOutput, SLOT (stopStream ()));
connect (&m_soundOutput, &SoundOutput::error, this, &MainWindow::showSoundOutError);
// connect (&m_soundOutput, &SoundOutput::status, this, &MainWindow::showStatusMessage);
connect (this, SIGNAL (outAttenuationChanged (qreal)), &m_soundOutput, SLOT (setAttenuation (qreal)));
// hook up Modulator slots
connect (this, SIGNAL (muteAudioOutput (bool)), &m_modulator, SLOT (mute (bool)));
connect (this, SIGNAL(transmitFrequency (unsigned)), &m_modulator, SLOT (setFrequency (unsigned)));
connect (this, SIGNAL (endTransmitMessage ()), &m_modulator, SLOT (close ()));
connect (this, SIGNAL (tune (bool)), &m_modulator, SLOT (tune (bool)));
connect (
this
, SIGNAL (sendMessage (unsigned, double, unsigned, AudioDevice::Channel, bool, double))
, &m_modulator
, SLOT (open (unsigned, double, unsigned, AudioDevice::Channel, bool, double))
);
// start the sound output thread
m_soundOutputThread.start (QThread::HighPriority);
// setup the waterfall
connect(m_wideGraph.data (), SIGNAL(freezeDecode2(int)),this,
SLOT(freezeDecode(int)));
connect(m_wideGraph.data (), SIGNAL(f11f12(int)),this,
SLOT(bumpFqso(int)));
connect(m_wideGraph.data (), SIGNAL(setXIT2(int)),this,
SLOT(setXIT(int)));
// connect(m_wideGraph.data (), SIGNAL(dialFreqChanged(double)),this,
// SLOT(dialFreqChanged2(double)));
connect (this, &MainWindow::finished, m_wideGraph.data (), &WideGraph::close);
// setup the log QSO dialog
connect (m_logDlg.data (), SIGNAL (acceptQSO (bool)), this, SLOT (acceptQSO2 (bool)));
on_EraseButton_clicked();
QActionGroup* modeGroup = new QActionGroup(this);
ui->actionJT9_1->setActionGroup(modeGroup);
ui->actionJT65->setActionGroup(modeGroup);
ui->actionJT9_JT65->setActionGroup(modeGroup);
QActionGroup* saveGroup = new QActionGroup(this);
ui->actionNone->setActionGroup(saveGroup);
ui->actionSave_decoded->setActionGroup(saveGroup);
ui->actionSave_all->setActionGroup(saveGroup);
QActionGroup* DepthGroup = new QActionGroup(this);
ui->actionQuickDecode->setActionGroup(DepthGroup);
ui->actionMediumDecode->setActionGroup(DepthGroup);
ui->actionDeepestDecode->setActionGroup(DepthGroup);
QButtonGroup* txMsgButtonGroup = new QButtonGroup;
txMsgButtonGroup->addButton(ui->txrb1,1);
txMsgButtonGroup->addButton(ui->txrb2,2);
txMsgButtonGroup->addButton(ui->txrb3,3);
txMsgButtonGroup->addButton(ui->txrb4,4);
txMsgButtonGroup->addButton(ui->txrb5,5);
txMsgButtonGroup->addButton(ui->txrb6,6);
connect(txMsgButtonGroup,SIGNAL(buttonClicked(int)),SLOT(set_ntx(int)));
connect(ui->decodedTextBrowser2,SIGNAL(selectCallsign(bool,bool)),this,
SLOT(doubleClickOnCall(bool,bool)));
connect(ui->decodedTextBrowser,SIGNAL(selectCallsign(bool,bool)),this,
SLOT(doubleClickOnCall2(bool,bool)));
setWindowTitle(Program_Title_Version);
connect(&m_detector, &Detector::framesWritten, this, &MainWindow::dataSink);
connect(&m_soundInput, SIGNAL(error(QString)), this,
SLOT(showSoundInError(QString)));
// connect(&m_soundInput, SIGNAL(status(QString)), this,
// SLOT(showStatusMessage(QString)));
createStatusBar();
connect(&proc_jt9, SIGNAL(readyReadStandardOutput()),
this, SLOT(readFromStdout()));
connect(&proc_jt9, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(jt9_error()));
connect(&proc_jt9, SIGNAL(readyReadStandardError()),
this, SLOT(readFromStderr()));
ui->bandComboBox->setEditable(true);
ui->bandComboBox->lineEdit()->setReadOnly(true);
ui->bandComboBox->lineEdit()->setAlignment(Qt::AlignCenter);
for(int i = 0; i < ui->bandComboBox->count(); i++)
ui->bandComboBox->setItemData(i, Qt::AlignCenter, Qt::TextAlignmentRole);
ui->tx5->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->tx5, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(showMacros(const QPoint&)));
ui->freeTextMsg->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->freeTextMsg, SIGNAL(customContextMenuRequested(const QPoint&)),
this, SLOT(showMacros(const QPoint&)));
QFont font=ui->decodedTextBrowser->font();
font.setPointSize(fontSize2);
font.setWeight(fontWeight2);
ui->decodedTextBrowser->setFont(font);
ui->decodedTextBrowser2->setFont(font);
m_logBook.setDisplayFont(font);
font=ui->readFreq->font();
font.setFamily("helvetica");
font.setPointSize(9);
font.setWeight(75);
ui->readFreq->setFont(font);
connect(&m_guiTimer, SIGNAL(timeout()), this, SLOT(guiUpdate()));
m_guiTimer.start(100); //Don't change the 100 ms!
ptt0Timer = new QTimer(this);
ptt0Timer->setSingleShot(true);
connect (ptt0Timer, SIGNAL (timeout ()), &m_modulator, SLOT (close ()));
connect(ptt0Timer, SIGNAL(timeout()), this, SLOT(stopTx2()));
ptt1Timer = new QTimer(this);
ptt1Timer->setSingleShot(true);
connect(ptt1Timer, SIGNAL(timeout()), this, SLOT(startTx2()));
logQSOTimer = new QTimer(this);
logQSOTimer->setSingleShot(true);
connect(logQSOTimer, SIGNAL(timeout()), this, SLOT(on_logQSOButton_clicked()));
tuneButtonTimer= new QTimer(this);
tuneButtonTimer->setSingleShot(true);
connect (tuneButtonTimer, SIGNAL (timeout ()), &m_modulator, SLOT (close ()));
connect(tuneButtonTimer, SIGNAL(timeout()), this,
SLOT(on_stopTxButton_clicked()));
killFileTimer = new QTimer(this);
killFileTimer->setSingleShot(true);
connect(killFileTimer, SIGNAL(timeout()), this, SLOT(killFile()));
m_auto=false;
m_waterfallAvg = 1;
m_txFirst=false;
Q_EMIT muteAudioOutput (false);
m_btxMute=false;
m_btxok=false;
m_restart=false;
m_transmitting=false;
m_killAll=false;
m_widebandDecode=false;
m_ntx=1;
m_myCall="";
m_myGrid="FN20qi";
m_appDir = QApplication::applicationDirPath();
m_saveDir="/users/joe/wsjtx/install/save";
m_rxFreq=1500;
m_txFreq=1500;
m_setftx=0;
m_loopall=false;
m_startAnother=false;
m_saveDecoded=false;
m_saveAll=false;
m_sec0=-1;
m_palette="Linrad";
m_RxLog=1; //Write Date and Time to RxLog
m_nutc0=9999;
m_mode="JT9";
m_rpt="-15";
m_TRperiod=60;
m_inGain=0;
m_dataAvailable=false;
g_iptt=0;
g_COMportOpen=0;
m_secID=0;
m_promptToLog=false;
m_blankLine=false;
m_insertBlank=false;
m_displayDXCCEntity=false;
m_clearCallGrid=false;
m_bMiles=false;
m_decodedText2=false;
m_freeText=false;
m_msErase=0;
m_sent73=false;
m_watchdogLimit=5;
m_tune=false;
m_repeatMsg=0;
m_bRigOpen=false;
m_secBandChanged=0;
m_bMultipleOK=false;
m_dontReadFreq=false;
m_lockTxFreq=false;
ui->readFreq->setEnabled(false);
m_QSOmsg="";
m_CATerror=false;
decodeBusy(false);
signalMeter = new SignalMeter(ui->meterFrame);
signalMeter->resize(50, 160);
ui->labAz->setStyleSheet("border: 0px;");
ui->labDist->setStyleSheet("border: 0px;");
mem_jt9 = shdmem;
// Multiple instances:
mykey_jt9 = thekey;
#ifdef WIN32
if(!m_bMultipleOK) {
while(true) {
int iret=killbyname("jt9.exe");
if(iret == 603) break;
if(iret != 0) msgBox("KillByName return code: " +
QString::number(iret));
}
}
#endif
//Band Settings
readSettings(); //Restore user's setup params
if(m_dFreq.length()<=1) { //Use the startup default frequencies and band descriptions
// default bands and JT65 frequencies
const double dFreq[]={0.13613,0.4742,1.838,3.576,5.357,7.076,10.138,14.076,
18.102,21.076,24.917,28.076,50.276,70.091,144.489,432.178};
const QStringList dBandDescription = QStringList() << "2200 m" << "630 m" << "160 m"
<< "80 m" << "60 m" << "40 m"
<< "30 m" << "20 m" << "17 m"
<< "15 m" << "12 m" << "10 m"
<< "6 m" << "4 m" << "2 m"
<< "other";
m_dFreq.clear();
m_antDescription.clear();
m_bandDescription.clear();
for(int i=0; i<16; i++) {
QString t;
t.sprintf("%f",dFreq[i]);
m_dFreq.append(t);
m_antDescription.append("");
m_bandDescription.append(dBandDescription[i]);
}
}
ui->bandComboBox->clear();
ui->bandComboBox->addItems(m_bandDescription);
ui->bandComboBox->setCurrentIndex(m_band);
QFile lockFile(m_appDir + "/.lock"); //Create .lock so jt9 will wait
lockFile.open(QIODevice::ReadWrite);
//QFile quitFile(m_appDir + "/.lock");
//quitFile.remove();
// Multiple instances: make the Qstring key into command line arg
// Multiple instances: start "jt9 -s <thekey>"
QByteArray ba = mykey_jt9->toLocal8Bit();
const char *bc = ba.data();
proc_jt9.start(QDir::toNativeSeparators('"' + m_appDir + '"' + "/jt9 -s " + bc));
m_pbdecoding_style1="QPushButton{background-color: cyan; \
border-style: outset; border-width: 1px; border-radius: 5px; \
border-color: black; min-width: 5em; padding: 3px;}";
m_pbmonitor_style="QPushButton{background-color: #00ff00; \
border-style: outset; border-width: 1px; border-radius: 5px; \
border-color: black; min-width: 5em; padding: 3px;}";
m_pbAutoOn_style="QPushButton{background-color: red; \
border-style: outset; border-width: 1px; border-radius: 5px; \
border-color: black; min-width: 5em; padding: 3px;}";
m_pbTune_style="QPushButton{background-color: red; \
border-style: outset; border-width: 1px; border-radius: 5px; \
border-color: black; min-width: 5em; padding: 3px;}";
genStdMsgs(m_rpt);
m_ntx=6;
ui->txrb6->setChecked(true);
if(m_mode!="JT9" and m_mode!="JT65" and m_mode!="JT9+JT65") m_mode="JT9";
on_actionWide_Waterfall_triggered(); //###
m_wideGraph->setRxFreq(m_rxFreq);
m_wideGraph->setTxFreq(m_txFreq);
m_wideGraph->setLockTxFreq(m_lockTxFreq);
m_wideGraph->setModeTx(m_mode);
m_wideGraph->setModeTx(m_modeTx);
dialFreqChanged2(m_dialFreq);
connect(m_wideGraph.data (), SIGNAL(setFreq3(int,int)),this,
SLOT(setFreq4(int,int)));
if(m_mode=="JT9") on_actionJT9_1_triggered();
if(m_mode=="JT65") on_actionJT65_triggered();
if(m_mode=="JT9+JT65") on_actionJT9_JT65_triggered();
future1 = new QFuture<void>;
watcher1 = new QFutureWatcher<void>;
connect(watcher1, SIGNAL(finished()),this,SLOT(diskDat()));
future2 = new QFuture<void>;
watcher2 = new QFutureWatcher<void>;
connect(watcher2, SIGNAL(finished()),this,SLOT(diskWriteFinished()));
m_detector.open (m_audioInputChannel);
m_soundInput.start(m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector);
Q_EMIT transmitFrequency (m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0));
Q_EMIT muteAudioOutput (false);
m_monitoring=!m_monitorStartOFF; // Start with Monitoring ON/OFF
m_detector.setMonitoring(m_monitoring);
m_diskData=false;
// Create "m_worked", a dictionary of all calls in wsjtx.log
QFile f("wsjtx.log");
f.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&f);
QString line,t,callsign;
for(int i=0; i<99999; i++) {
line=in.readLine();
if(line.length()<=0) break;
t=line.mid(18,12);
callsign=t.mid(0,t.indexOf(","));
}
f.close();
ui->decodedTextLabel->setFont(ui->decodedTextBrowser->font());
ui->decodedTextLabel2->setFont(ui->decodedTextBrowser2->font());
t="UTC dB DT Freq Message";
ui->decodedTextLabel->setText(t);
ui->decodedTextLabel2->setText(t);
psk_Reporter = new PSK_Reporter(this);
psk_Reporter->setLocalStation(m_myCall,m_myGrid, m_antDescription[m_band], "WSJT-X r" + rev.mid(6,4) );
m_logBook.init();
ui->label_9->setStyleSheet("QLabel{background-color: #aabec8}");
ui->label_10->setStyleSheet("QLabel{background-color: #aabec8}");
ui->labUTC->setStyleSheet( \
"QLabel { background-color : black; color : yellow; }");
ui->labDialFreq->setStyleSheet( \
"QLabel { background-color : black; color : yellow; }");
QFile f2("ALL.TXT");
f2.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append);
QTextStream out(&f2);
out << QDateTime::currentDateTimeUtc().toString("yyyy-MMM-dd hh:mm")
<< " " << m_dialFreq << " MHz " << m_mode << endl;
f2.close();
} // End of MainWindow constructor
//--------------------------------------------------- MainWindow destructor
MainWindow::~MainWindow()
{
if(!m_decoderBusy) {
QFile lockFile(m_appDir + "/.lock");
lockFile.remove();
}
delete ui;
}
//-------------------------------------------------------- writeSettings()
void MainWindow::writeSettings()
{
m_settings->beginGroup("MainWindow");
m_settings->setValue ("geometry", saveGeometry ());
m_settings->setValue ("state", saveState ());
m_settings->setValue("MRUdir", m_path);
m_settings->setValue("TxFirst",m_txFirst);
m_settings->setValue("DXcall",ui->dxCallEntry->text());
m_settings->setValue("DXgrid",ui->dxGridEntry->text());
m_settings->endGroup();
m_settings->beginGroup("Common");
m_settings->setValue("MyCall",m_myCall);
m_settings->setValue("MyGrid",m_myGrid);
m_settings->setValue("IDint",m_idInt);
m_settings->setValue("PTTmethod",m_pttMethodIndex);
m_settings->setValue("PTTport",m_pttPort);
m_settings->setValue("SaveDir",m_saveDir);
m_settings->setValue("SoundInName", m_audioInputDevice.deviceName ());
m_settings->setValue("SoundOutName", m_audioOutputDevice.deviceName ());
m_settings->setValue ("AudioInputChannel", AudioDevice::toString (m_audioInputChannel));
m_settings->setValue ("AudioOutputChannel", AudioDevice::toString (m_audioOutputChannel));
m_settings->setValue("Mode",m_mode);
m_settings->setValue("ModeTx",m_modeTx);
m_settings->setValue("SaveNone",ui->actionNone->isChecked());
m_settings->setValue("SaveDecoded",ui->actionSave_decoded->isChecked());
m_settings->setValue("SaveAll",ui->actionSave_all->isChecked());
m_settings->setValue("NDepth",m_ndepth);
m_settings->setValue("MonitorOFF",m_monitorStartOFF);
m_settings->setValue("DialFreq",m_dialFreq);
m_settings->setValue("RxFreq",m_rxFreq);
m_settings->setValue("TxFreq",m_txFreq);
m_settings->setValue("InGain",m_inGain);
m_settings->setValue("OutAttenuation", ui->outAttenuation->value ());
m_settings->setValue("PSKReporter",m_pskReporter);
m_settings->setValue("After73",m_After73);
m_settings->setValue("Macros",m_macro);
//Band Settings
m_settings->setValue("BandFrequencies",m_dFreq);
m_settings->setValue("BandDescriptions",m_bandDescription);
m_settings->setValue("AntennaDescriptions",m_antDescription);
m_settings->setValue("toRTTY",m_toRTTY);
m_settings->setValue("NoSuffix",m_noSuffix);
m_settings->setValue("dBtoComments",m_dBtoComments);
m_settings->setValue("catEnabled",m_catEnabled);
m_settings->setValue("Rig",m_rig);
m_settings->setValue("RigIndex",m_rigIndex);
m_settings->setValue("CATport",m_catPort);
m_settings->setValue("CATportIndex",m_catPortIndex);
m_settings->setValue("SerialRate",m_serialRate);
m_settings->setValue("SerialRateIndex",m_serialRateIndex);
m_settings->setValue("DataBits",m_dataBits);
m_settings->setValue("DataBitsIndex",m_dataBitsIndex);
m_settings->setValue("StopBits",m_stopBits);
m_settings->setValue("StopBitsIndex",m_stopBitsIndex);
m_settings->setValue("Handshake",m_handshake);
m_settings->setValue("HandshakeIndex",m_handshakeIndex);
m_settings->setValue("BandIndex",m_band);
m_settings->setValue("PromptToLog",m_promptToLog);
m_settings->setValue("InsertBlank",m_insertBlank);
m_settings->setValue("DXCCEntity",m_displayDXCCEntity);
m_settings->setValue("ClearCallGrid",m_clearCallGrid);
m_settings->setValue("Miles",m_bMiles);
m_settings->setValue("GUItab",ui->tabWidget->currentIndex());
m_settings->setValue("QuickCall",m_quickCall);
m_settings->setValue("73TxDisable",m_73TxDisable);
m_settings->setValue("Runaway",m_runaway);
m_settings->setValue("Tx2QSO",m_tx2QSO);
m_settings->setValue("MultipleOK",m_bMultipleOK);
m_settings->setValue("DTR",m_bDTR);
m_settings->setValue("RTS",m_bRTS); m_settings->setValue("pttData",m_pttData);
m_settings->setValue("Polling",m_poll);
m_settings->setValue("OutBufSize",outBufSize);
m_settings->setValue("LockTxFreq",m_lockTxFreq);
m_settings->setValue("TxSplit",m_bSplit);
m_settings->setValue("UseXIT",m_bXIT);
m_settings->setValue("XIT",m_XIT);
m_settings->setValue("Plus2kHz",m_plus2kHz);
m_settings->endGroup();
}
//---------------------------------------------------------- readSettings()
void MainWindow::readSettings()
{
m_settings->beginGroup("MainWindow");
restoreGeometry (m_settings->value ("geometry", saveGeometry ()).toByteArray ());
restoreState (m_settings->value ("state", saveState ()).toByteArray ());
ui->dxCallEntry->setText(m_settings->value("DXcall","").toString());
ui->dxGridEntry->setText(m_settings->value("DXgrid","").toString());
m_path = m_settings->value("MRUdir", m_appDir + "/save").toString();
m_txFirst = m_settings->value("TxFirst",false).toBool();
ui->txFirstCheckBox->setChecked(m_txFirst);
m_settings->endGroup();
m_settings->beginGroup("Common");
m_myCall=m_settings->value("MyCall","").toString();
morse_(m_myCall.toLatin1().data(),icw,&m_ncw,m_myCall.length());
m_myGrid=m_settings->value("MyGrid","").toString();
m_idInt=m_settings->value("IDint",0).toInt();
m_pttMethodIndex=m_settings->value("PTTmethod",1).toInt();
m_pttPort=m_settings->value("PTTport",0).toInt();
m_saveDir=m_settings->value("SaveDir",m_appDir + "/save").toString();
{
//
// retrieve audio input device
//
QString savedName = m_settings->value( "SoundInName").toString();
QList<QAudioDeviceInfo> audioInputDevices (QAudioDeviceInfo::availableDevices (QAudio::AudioInput)); // available audio input devices
for (QList<QAudioDeviceInfo>::const_iterator p = audioInputDevices.begin (); p != audioInputDevices.end (); ++p)
{
if (p->deviceName () == savedName)
{
m_audioInputDevice = *p;
}
}
}
{
//
// retrieve audio output device
//
QString savedName = m_settings->value("SoundOutName").toString();
QList<QAudioDeviceInfo> audioOutputDevices (QAudioDeviceInfo::availableDevices (QAudio::AudioOutput)); // available audio output devices
for (QList<QAudioDeviceInfo>::const_iterator p = audioOutputDevices.begin (); p != audioOutputDevices.end (); ++p)
{
if (p->deviceName () == savedName) {
m_audioOutputDevice = *p;
}
}
}
// retrieve audio channel info
m_audioInputChannel = AudioDevice::fromString (m_settings->value ("AudioInputChannel", "Mono").toString ());
m_audioOutputChannel = AudioDevice::fromString (m_settings->value ("AudioOutputChannel", "Mono").toString ());
m_mode=m_settings->value("Mode","JT9").toString();
m_modeTx=m_settings->value("ModeTx","JT9").toString();
if(m_modeTx=="JT9") ui->pbTxMode->setText("Tx JT9 @");
if(m_modeTx=="JT65") ui->pbTxMode->setText("Tx JT65 #");
ui->actionNone->setChecked(m_settings->value("SaveNone",true).toBool());
ui->actionSave_decoded->setChecked(m_settings->value(
"SaveDecoded",false).toBool());
ui->actionSave_all->setChecked(m_settings->value("SaveAll",false).toBool());
m_dialFreq=m_settings->value("DialFreq",14.078).toDouble();
m_rxFreq=m_settings->value("RxFreq",1500).toInt();
ui->RxFreqSpinBox->setValue(m_rxFreq);
m_txFreq=m_settings->value("TxFreq",1500).toInt();
ui->TxFreqSpinBox->setValue(m_txFreq);
Q_EMIT transmitFrequency (m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0));
m_saveDecoded=ui->actionSave_decoded->isChecked();
m_saveAll=ui->actionSave_all->isChecked();
m_ndepth=m_settings->value("NDepth",3).toInt();
m_inGain=m_settings->value("InGain",0).toInt();
ui->inGain->setValue(m_inGain);
// setup initial value of tx attenuator
ui->outAttenuation->setValue (m_settings->value ("OutAttenuation", 0).toInt ());
on_outAttenuation_valueChanged (ui->outAttenuation->value ());
m_monitorStartOFF=m_settings->value("MonitorOFF",false).toBool();
ui->actionMonitor_OFF_at_startup->setChecked(m_monitorStartOFF);
m_pskReporter=m_settings->value("PSKReporter",false).toBool();
m_After73=m_settings->value("After73",false).toBool();
m_macro=m_settings->value("Macros","TNX 73 GL").toStringList();
//Band Settings
m_dFreq=m_settings->value("BandFrequencies","").toStringList();
m_bandDescription=m_settings->value("BandDescriptions","").toStringList();
m_antDescription=m_settings->value("AntennaDescriptions","").toStringList();
m_toRTTY=m_settings->value("toRTTY",false).toBool();
ui->actionConvert_JT9_x_to_RTTY->setChecked(m_toRTTY);
m_noSuffix=m_settings->value("NoSuffix",false).toBool();
m_dBtoComments=m_settings->value("dBtoComments",false).toBool();
ui->actionLog_dB_reports_to_Comments->setChecked(m_dBtoComments);
m_rig=m_settings->value("Rig",214).toInt();
m_rigIndex=m_settings->value("RigIndex",100).toInt();
m_catPort=m_settings->value("CATport","None").toString();
m_catPortIndex=m_settings->value("CATportIndex",0).toInt();
m_serialRate=m_settings->value("SerialRate",4800).toInt();
m_serialRateIndex=m_settings->value("SerialRateIndex",1).toInt();
m_dataBits=m_settings->value("DataBits",8).toInt();
m_dataBitsIndex=m_settings->value("DataBitsIndex",1).toInt();
m_stopBits=m_settings->value("StopBits",2).toInt();
m_stopBitsIndex=m_settings->value("StopBitsIndex",1).toInt();
m_handshake=m_settings->value("Handshake","None").toString();
m_handshakeIndex=m_settings->value("HandshakeIndex",0).toInt();
m_band=m_settings->value("BandIndex",7).toInt();
ui->bandComboBox->setCurrentIndex(m_band);
dialFreqChanged2(m_dialFreq);
m_catEnabled=m_settings->value("catEnabled",false).toBool();
m_promptToLog=m_settings->value("PromptToLog",false).toBool();
ui->actionPrompt_to_log_QSO->setChecked(m_promptToLog);
m_insertBlank=m_settings->value("InsertBlank",false).toBool();
ui->actionBlank_line_between_decoding_periods->setChecked(m_insertBlank);
m_displayDXCCEntity=m_settings->value("DXCCEntity",false).toBool();
ui->actionEnable_DXCC_entity->setChecked(m_displayDXCCEntity);
m_clearCallGrid=m_settings->value("ClearCallGrid",false).toBool();
ui->actionClear_DX_Call_and_Grid_after_logging->setChecked(m_clearCallGrid);
m_bMiles=m_settings->value("Miles",false).toBool();
ui->actionDisplay_distance_in_miles->setChecked(m_bMiles);
int n=m_settings->value("GUItab",0).toInt();
ui->tabWidget->setCurrentIndex(n);
m_quickCall=m_settings->value("QuickCall",false).toBool();
ui->actionDouble_click_on_call_sets_Tx_Enable->setChecked(m_quickCall);
m_73TxDisable=m_settings->value("73TxDisable",false).toBool();
ui->action_73TxDisable->setChecked(m_73TxDisable);
m_runaway=m_settings->value("Runaway",false).toBool();
ui->actionRunaway_Tx_watchdog->setChecked(m_runaway);
m_tx2QSO=m_settings->value("Tx2QSO",false).toBool();
ui->actionTx2QSO->setChecked(m_tx2QSO);
m_bMultipleOK=m_settings->value("MultipleOK",false).toBool();
ui->actionAllow_multiple_instances->setChecked(m_bMultipleOK);
m_bDTR=m_settings->value("DTR",false).toBool();
m_bRTS=m_settings->value("RTS",false).toBool(); m_pttData=m_settings->value("pttData",false).toBool();
m_poll=m_settings->value("Polling",0).toInt();
outBufSize=m_settings->value("OutBufSize",4096).toInt();
m_lockTxFreq=m_settings->value("LockTxFreq",false).toBool();
ui->cbTxLock->setChecked(m_lockTxFreq);
m_bSplit=m_settings->value("TxSplit",false).toBool();
m_bXIT=m_settings->value("UseXIT",false).toBool();
m_XIT=m_settings->value("XIT",0).toInt();
m_plus2kHz=m_settings->value("Plus2kHz",false).toBool();
ui->cbPlus2kHz->setChecked(m_plus2kHz);
m_settings->endGroup();
if(m_ndepth==1) ui->actionQuickDecode->setChecked(true);
if(m_ndepth==2) ui->actionMediumDecode->setChecked(true);
if(m_ndepth==3) ui->actionDeepestDecode->setChecked(true);
statusChanged();
}
//-------------------------------------------------------------- dataSink()
void MainWindow::dataSink(qint64 frames)
{
static float s[NSMAX];
static int ihsym=0;
static int nzap=0;
static int trmin;
static int npts8;
static float px=0.0;
static float df3;
static float slope;
if(m_diskData) {
jt9com_.ndiskdat=1;
} else {
jt9com_.ndiskdat=0;
}
// Get power, spectrum, and ihsym
trmin=m_TRperiod/60;
slope=0.0;
slope=(float)m_wideGraph->getSlope();
int k (frames - 1);
symspec_(&k,&trmin,&m_nsps,&m_inGain,&slope,&px,s,&df3,&ihsym,&npts8);
if(ihsym <=0) return;
QString t;
m_pctZap=nzap*100.0/m_nsps;
t.sprintf(" Rx noise: %5.1f ",px);
signalMeter->setValue(px); // Update thermometer
if(m_monitoring || m_diskData) {
m_wideGraph->dataSink2(s,df3,ihsym,m_diskData);
}
if(ihsym == m_hsymStop) {
m_dataAvailable=true;
jt9com_.npts8=(ihsym*m_nsps)/16;
jt9com_.newdat=1;
jt9com_.nagain=0;
jt9com_.nzhsym=m_hsymStop;
QDateTime t = QDateTime::currentDateTimeUtc();
m_dateTime=t.toString("yyyy-MMM-dd hh:mm");
decode(); //Start decoder
if(!m_diskData) { //Always save; may delete later
int ihr=t.time().toString("hh").toInt();
int imin=t.time().toString("mm").toInt();
imin=imin - (imin%(m_TRperiod/60));
QString t2;
t2.sprintf("%2.2d%2.2d",ihr,imin);
m_fname=m_saveDir + "/" + t.date().toString("yyMMdd") + "_" +
t2 + ".wav";
*future2 = QtConcurrent::run(savewav, m_fname, m_TRperiod);
watcher2->setFuture(*future2);
}
}
}
void MainWindow::showSoundInError(const QString& errorMsg)
{QMessageBox::critical(this, tr("Error in SoundInput"), errorMsg);}
void MainWindow::showSoundOutError(const QString& errorMsg)
{QMessageBox::critical(this, tr("Error in SoundOutput"), errorMsg);}
void MainWindow::showStatusMessage(const QString& statusMsg)
{statusBar()->showMessage(statusMsg);}
void MainWindow::on_actionDeviceSetup_triggered() //Setup Dialog
{
DevSetup dlg(this);
dlg.m_myCall=m_myCall;
dlg.m_myGrid=m_myGrid;
dlg.m_idInt=m_idInt;
dlg.m_pttMethodIndex=m_pttMethodIndex;
dlg.m_pttPort=m_pttPort;
dlg.m_saveDir=m_saveDir;
dlg.m_audioInputDevice = m_audioInputDevice;
dlg.m_audioOutputDevice = m_audioOutputDevice;
dlg.m_audioInputChannel = m_audioInputChannel;
dlg.m_audioOutputChannel = m_audioOutputChannel;
dlg.m_pskReporter=m_pskReporter;
dlg.m_After73=m_After73;
dlg.m_macro=m_macro;
dlg.m_dFreq=m_dFreq;
dlg.m_antDescription=m_antDescription;
dlg.m_bandDescription=m_bandDescription;
dlg.m_catEnabled=m_catEnabled;
dlg.m_rig=m_rig;
dlg.m_rigIndex=m_rigIndex;
dlg.m_catPort=m_catPort;
dlg.m_catPortIndex=m_catPortIndex;
dlg.m_serialRate=m_serialRate;
dlg.m_serialRateIndex=m_serialRateIndex;
dlg.m_dataBits=m_dataBits;
dlg.m_dataBitsIndex=m_dataBitsIndex;
dlg.m_stopBits=m_stopBits;
dlg.m_stopBitsIndex=m_stopBitsIndex;
dlg.m_handshake=m_handshake;
dlg.m_handshakeIndex=m_handshakeIndex;
dlg.m_bDTR=m_bDTR;
dlg.m_bRTS=m_bRTS; dlg.m_pttData=m_pttData;
dlg.m_poll=m_poll;
dlg.m_bSplit=m_bSplit;
dlg.m_bXIT=m_bXIT;
if(m_bRigOpen) {
rig->close();
ui->readFreq->setStyleSheet("");
ui->readFreq->setEnabled(false);
if(m_rig<9900) delete rig;
m_bRigOpen=false;
m_catEnabled=false;
m_CATerror=false;
}
dlg.initDlg();
if(dlg.exec() == QDialog::Accepted) {
m_myCall=dlg.m_myCall;
m_myGrid=dlg.m_myGrid;
m_idInt=dlg.m_idInt;
m_pttMethodIndex=dlg.m_pttMethodIndex;
m_pttPort=dlg.m_pttPort;
m_saveDir=dlg.m_saveDir;
m_audioInputDevice = dlg.m_audioInputDevice;
m_audioOutputDevice = dlg.m_audioOutputDevice;
m_audioInputChannel = dlg.m_audioInputChannel;
m_audioOutputChannel = dlg.m_audioOutputChannel;
m_macro=dlg.m_macro;
m_dFreq=dlg.m_dFreq;
m_antDescription=dlg.m_antDescription;
m_bandDescription=dlg.m_bandDescription;
m_catEnabled=dlg.m_catEnabled;
m_rig=dlg.m_rig;
m_rigIndex=dlg.m_rigIndex;
m_catPort=dlg.m_catPort;
m_catPortIndex=dlg.m_catPortIndex;
m_serialRate=dlg.m_serialRate;
m_serialRateIndex=dlg.m_serialRateIndex;
m_dataBits=dlg.m_dataBits;
m_dataBitsIndex=dlg.m_dataBitsIndex;
m_stopBits=dlg.m_stopBits;
m_stopBitsIndex=dlg.m_stopBitsIndex;
m_handshake=dlg.m_handshake;
m_handshakeIndex=dlg.m_handshakeIndex;
m_bDTR=dlg.m_bDTR;
m_bRTS=dlg.m_bRTS;
m_pttData=dlg.m_pttData;
m_poll=dlg.m_poll;
//Band Settings
ui->bandComboBox->clear();
ui->bandComboBox->addItems(dlg.m_bandDescription);
ui->bandComboBox->setCurrentIndex(m_band);
m_pskReporter=dlg.m_pskReporter;
if(m_pskReporter) {
psk_Reporter->setLocalStation(m_myCall, m_myGrid, m_antDescription[m_band], "WSJT-X r" + rev.mid(6,4) );
}
m_After73=dlg.m_After73;
if(dlg.m_restartSoundIn) {
m_soundInput.stop ();
m_detector.close ();
m_detector.open (m_audioInputChannel);
m_soundInput.start(m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector);
}
if(dlg.m_restartSoundOut) {
Q_EMIT stopAudioOutputStream ();
Q_EMIT startAudioOutputStream (m_audioOutputDevice, AudioDevice::Mono == m_audioOutputChannel ? 1 : 2);
}
}
m_catEnabled=dlg.m_catEnabled;
if(m_catEnabled) {
rigOpen();
} else {
ui->readFreq->setStyleSheet("");
}
if(dlg.m_bSplit!=m_bSplit or dlg.m_bXIT!=m_bXIT) {
m_bSplit=dlg.m_bSplit;
if(m_bSplit) ui->readFreq->setText("S");
if(!m_bSplit) ui->readFreq->setText("");
m_bXIT=dlg.m_bXIT;
if(m_bSplit or m_bXIT) setXIT(m_txFreq);
if(m_bRigOpen and !m_bSplit) {
int ret=rig->setSplitFreq(MHz(m_dialFreq),RIG_VFO_B);
if(ret!=RIG_OK) {
QString rt;
rt.sprintf("Setting VFO_B failed: %d",ret);
msgBox(rt);
}
}
}
}
void MainWindow::on_monitorButton_clicked() //Monitor
{
m_monitoring=true;
m_detector.setMonitoring(true);
// m_soundInput.start(m_audioInputDevice, AudioDevice::Mono == m_audioInputChannel ? 1 : 2, RX_SAMPLE_RATE / 10, &m_detector);
m_diskData=false;
}
void MainWindow::on_actionAbout_triggered() //Display "About"
{
CAboutDlg dlg(this,Program_Title_Version);
dlg.exec();
}
void MainWindow::on_autoButton_clicked() //Auto
{
m_auto = !m_auto;
if(m_auto) {
ui->autoButton->setStyleSheet(m_pbAutoOn_style);
} else {
m_btxok=false;
Q_EMIT muteAudioOutput ();
ui->autoButton->setStyleSheet("");
on_monitorButton_clicked();
m_repeatMsg=0;
}
}
void MainWindow::keyPressEvent( QKeyEvent *e ) //keyPressEvent
{
int n;
switch(e->key())
{
case Qt::Key_1:
if(e->modifiers() & Qt::AltModifier) {
on_txb1_clicked();
break;
}
case Qt::Key_2:
if(e->modifiers() & Qt::AltModifier) {
on_txb2_clicked();
break;
}
case Qt::Key_3:
if(e->modifiers() & Qt::AltModifier) {
on_txb3_clicked();
break;
}
case Qt::Key_4:
if(e->modifiers() & Qt::AltModifier) {
on_txb4_clicked();
break;
}
case Qt::Key_5:
if(e->modifiers() & Qt::AltModifier) {
on_txb5_clicked();
break;
}
case Qt::Key_6:
if(e->modifiers() & Qt::AltModifier) {
on_txb6_clicked();
break;
}
case Qt::Key_D:
if(e->modifiers() & Qt::ShiftModifier) {
if(!m_decoderBusy) {
jt9com_.newdat=0;
jt9com_.nagain=0;
decode();
break;
}
}
break;
case Qt::Key_F4:
ui->dxCallEntry->setText("");
ui->dxGridEntry->setText("");
genStdMsgs("");
m_ntx=6;
ui->txrb6->setChecked(true);
break;
case Qt::Key_F6:
if(e->modifiers() & Qt::ShiftModifier) {
on_actionDecode_remaining_files_in_directory_triggered();
}
break;
case Qt::Key_F11:
n=11;
if(e->modifiers() & Qt::ControlModifier) n+=100;
bumpFqso(n);
break;
case Qt::Key_F12:
n=12;
if(e->modifiers() & Qt::ControlModifier) n+=100;
bumpFqso(n);
break;
case Qt::Key_F:
if(e->modifiers() & Qt::ControlModifier) {
if(ui->tabWidget->currentIndex()==0) {
ui->tx5->clear();
ui->tx5->setFocus();
} else {
ui->freeTextMsg->clear();
ui->freeTextMsg->setFocus();
}
break;
}
case Qt::Key_G:
if(e->modifiers() & Qt::AltModifier) {
genStdMsgs(m_rpt);
break;
}
case Qt::Key_H:
if(e->modifiers() & Qt::AltModifier) {
on_stopTxButton_clicked();
break;
}
case Qt::Key_L:
if(e->modifiers() & Qt::ControlModifier) {
lookup();
genStdMsgs(m_rpt);
break;
}
case Qt::Key_V:
if(e->modifiers() & Qt::AltModifier) {
m_fileToSave=m_fname;
break;
}
}
}
void MainWindow::bumpFqso(int n) //bumpFqso()
{
int i;
bool ctrl = (n>=100);
n=n%100;
i=m_wideGraph->rxFreq();
if(n==11) i--;
if(n==12) i++;
m_wideGraph->setRxFreq(i);
if(ctrl) {
ui->TxFreqSpinBox->setValue(i);
m_wideGraph->setTxFreq(i);
}
}
void MainWindow::dialFreqChanged2(double f)
{
m_dialFreq=f;
if(m_band<0 or m_band>15 or m_dFreq.length()<=1) return;
QString t;
t.sprintf("%.6f",m_dialFreq);
int n=t.length();
t=t.mid(0,n-3) + " " + t.mid(n-3,3);
double fBand=m_dFreq[m_band].toDouble();
if(qAbs(m_dialFreq-fBand)<0.01) {
ui->labDialFreq->setStyleSheet( \
"QLabel { background-color : black; color : yellow; }");
} else {
ui->labDialFreq->setStyleSheet( \
"QLabel { background-color : red; color : yellow; }");
ui->labDialFreq->setText(t);
}
ui->labDialFreq->setText(t);
statusChanged();
m_wideGraph->setDialFreq(m_dialFreq);
}
void MainWindow::statusChanged()
{
QFile f("wsjtx_status.txt");
if(f.open(QFile::WriteOnly | QIODevice::Text)) {
QTextStream out(&f);
out << m_dialFreq << ";" << m_mode << ";" << m_hisCall << ";"
<< ui->rptSpinBox->value() << ";" << m_modeTx << endl;
f.close();
} else {
msgBox("Cannot open file \"wsjtx_status.txt\".");
return;
}
}
bool MainWindow::eventFilter(QObject *object, QEvent *event) //eventFilter()
{
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
MainWindow::keyPressEvent(keyEvent);
return QObject::eventFilter(object, event);
}
return QObject::eventFilter(object, event);
}
void MainWindow::createStatusBar() //createStatusBar
{
lab1 = new QLabel("Receiving");
lab1->setAlignment(Qt::AlignHCenter);
lab1->setMinimumSize(QSize(80,18));
lab1->setStyleSheet("QLabel{background-color: #00ff00}");
lab1->setFrameStyle(QFrame::Panel | QFrame::Sunken);
statusBar()->addWidget(lab1);
lab2 = new QLabel("");
lab2->setAlignment(Qt::AlignHCenter);
lab2->setMinimumSize(QSize(80,18));
lab2->setFrameStyle(QFrame::Panel | QFrame::Sunken);
statusBar()->addWidget(lab2);
lab3 = new QLabel("");
lab3->setAlignment(Qt::AlignHCenter);
lab3->setMinimumSize(QSize(150,18));
lab3->setFrameStyle(QFrame::Panel | QFrame::Sunken);
statusBar()->addWidget(lab3);
}
void MainWindow::on_actionExit_triggered() //Exit()
{
OnExit();
}
void MainWindow::closeEvent(QCloseEvent * e)
{
writeSettings ();
OnExit();
QMainWindow::closeEvent (e);
}
void MainWindow::OnExit()
{
m_guiTimer.stop ();
if(m_fname != "") killFile();
m_killAll=true;
mem_jt9->detach();
QFile quitFile(m_appDir + "/.quit");
quitFile.open(QIODevice::ReadWrite);
QFile lockFile(m_appDir + "/.lock");
lockFile.remove(); // Allow jt9 to terminate
bool b=proc_jt9.waitForFinished(1000);
if(!b) proc_jt9.kill();
quitFile.remove();
Q_EMIT finished ();
m_soundOutputThread.wait ();
}
void MainWindow::on_stopButton_clicked() //stopButton
{
m_monitoring=false;
m_detector.setMonitoring(m_monitoring);
m_loopall=false;
}
void MainWindow::msgBox(QString t) //msgBox
{
msgBox0.setText(t);
msgBox0.exec();
}
void MainWindow::on_actionOnline_Users_Guide_triggered() //Display manual
{
QDesktopServices::openUrl(QUrl(
"http://www.physics.princeton.edu/pulsar/K1JT/WSJT-X_Users_Guide_v1.2.pdf",
QUrl::TolerantMode));
}
void MainWindow::on_actionWide_Waterfall_triggered() //Display Waterfalls
{
m_wideGraph->show();
}
void MainWindow::on_actionOpen_triggered() //Open File
{
m_monitoring=false;
m_detector.setMonitoring(m_monitoring);
QString fname;
fname=QFileDialog::getOpenFileName(this, "Open File", m_path,
"WSJT Files (*.wav)");
if(fname != "") {
m_path=fname;
int i;
i=fname.indexOf(".wav") - 11;
if(i>=0) {
lab1->setStyleSheet("QLabel{background-color: #66ff66}");
lab1->setText(" " + fname.mid(i,15) + " ");
}
on_stopButton_clicked();
m_diskData=true;
*future1 = QtConcurrent::run(getfile, fname, m_TRperiod);
watcher1->setFuture(*future1); // call diskDat() when done
}
}
void MainWindow::on_actionOpen_next_in_directory_triggered() //Open Next
{
int i,len;
QFileInfo fi(m_path);
QStringList list;
list= fi.dir().entryList().filter(".wav");
for (i = 0; i < list.size()-1; ++i) {
if(i==list.size()-2) m_loopall=false;
len=list.at(i).length();
if(list.at(i)==m_path.right(len)) {
int n=m_path.length();
QString fname=m_path.replace(n-len,len,list.at(i+1));
m_path=fname;
int i;
i=fname.indexOf(".wav") - 11;
if(i>=0) {
lab1->setStyleSheet("QLabel{background-color: #66ff66}");
lab1->setText(" " + fname.mid(i,len) + " ");
}
m_diskData=true;
*future1 = QtConcurrent::run(getfile, fname, m_TRperiod);
watcher1->setFuture(*future1);
return;
}
}
}
//Open all remaining files
void MainWindow::on_actionDecode_remaining_files_in_directory_triggered()
{
m_loopall=true;
on_actionOpen_next_in_directory_triggered();
}
void MainWindow::diskDat() //diskDat()
{
int k;
int kstep=m_nsps/2;
m_diskData=true;
for(int n=1; n<=m_hsymStop; n++) { // Do the half-symbol FFTs
k=(n+1)*kstep;
jt9com_.npts8=k/8;
dataSink(k * sizeof (jt9com_.d2[0]));
if(n%10 == 1 or n == m_hsymStop)
qApp->processEvents(); //Keep GUI responsive
}
}
void MainWindow::diskWriteFinished() //diskWriteFinished
{
}
//Delete ../save/*.wav
void MainWindow::on_actionDelete_all_wav_files_in_SaveDir_triggered()
{
int i;
QString fname;
int ret = QMessageBox::warning(this, "Confirm Delete",
"Are you sure you want to delete all *.wav files in\n" +
QDir::toNativeSeparators(m_saveDir) + " ?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if(ret==QMessageBox::Yes) {
QDir dir(m_saveDir);
QStringList files=dir.entryList(QDir::Files);
QList<QString>::iterator f;
for(f=files.begin(); f!=files.end(); ++f) {
fname=*f;
i=(fname.indexOf(".wav"));
if(i>10) dir.remove(fname);
}
}
}
void MainWindow::on_actionNone_triggered() //Save None
{
m_saveDecoded=false;
m_saveAll=false;
ui->actionNone->setChecked(true);
}
void MainWindow::on_actionSave_decoded_triggered()
{
m_saveDecoded=true;
m_saveAll=false;
ui->actionSave_decoded->setChecked(true);
}
void MainWindow::on_actionSave_all_triggered() //Save All
{
m_saveDecoded=false;
m_saveAll=true;
ui->actionSave_all->setChecked(true);
}
void MainWindow::on_actionKeyboard_shortcuts_triggered()
{
pShortcuts = new QTextEdit(0);
pShortcuts->setReadOnly(true);
pShortcuts->setFontPointSize(10);
pShortcuts->setWindowTitle("Keyboard Shortcuts");
pShortcuts->setGeometry(QRect(45,50,430,460));
Qt::WindowFlags flags = Qt::WindowCloseButtonHint |
Qt::WindowMinimizeButtonHint;
pShortcuts->setWindowFlags(flags);
QString shortcuts = m_appDir + "/shortcuts.txt";
QFile f(shortcuts);
if(!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
msgBox("Cannot open " + shortcuts);
return;
}
QTextStream s(&f);
QString t;
for(int i=0; i<100; i++) {
t=s.readLine();
pShortcuts->append(t);
if(s.atEnd()) break;
}
pShortcuts->show();
}
void MainWindow::on_actionSpecial_mouse_commands_triggered()
{
QTextEdit* pMouseCmnds;
pMouseCmnds = new QTextEdit(0);
pMouseCmnds->setReadOnly(true);
pMouseCmnds->setFontPointSize(10);
pMouseCmnds->setWindowTitle("Special Mouse Commands");
pMouseCmnds->setGeometry(QRect(45,50,440,300));
Qt::WindowFlags flags = Qt::WindowCloseButtonHint |
Qt::WindowMinimizeButtonHint;
pMouseCmnds->setWindowFlags(flags);
QString mouseCmnds = m_appDir + "/mouse_commands.txt";
QFile f(mouseCmnds);
if(!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
msgBox("Cannot open " + mouseCmnds);
return;
}
QTextStream s(&f);
QString t;
for(int i=0; i<100; i++) {
t=s.readLine();
pMouseCmnds->append(t);
if(s.atEnd()) break;
}
pMouseCmnds->show();
}
void MainWindow::on_DecodeButton_clicked() //Decode request
{
if(!m_decoderBusy) {
jt9com_.newdat=0;
jt9com_.nagain=1;
decode();
}
}
void MainWindow::freezeDecode(int n) //freezeDecode()
{
bool ctrl = (n>=100);
int i=m_wideGraph->rxFreq();
if(ctrl) {
ui->TxFreqSpinBox->setValue(i);
m_wideGraph->setTxFreq(i);
}
if((n%100)==2) on_DecodeButton_clicked();
}
void MainWindow::decode() //decode()
{
if(!m_dataAvailable) return;
ui->DecodeButton->setStyleSheet(m_pbdecoding_style1);
if(jt9com_.newdat==1 && (!m_diskData)) {
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
int imin=ms/60000;
int ihr=imin/60;
imin=imin % 60;
imin=imin - (imin % (m_TRperiod/60));
jt9com_.nutc=100*ihr + imin;
}
jt9com_.nfqso=m_wideGraph->rxFreq();
jt9com_.ndepth=m_ndepth;
jt9com_.ndiskdat=0;
if(m_diskData) jt9com_.ndiskdat=1;
jt9com_.nfa=m_wideGraph->nStartFreq();
jt9com_.nfSplit=m_wideGraph->getFmin();
jt9com_.nfb=m_wideGraph->getFmax();
jt9com_.ntol=20;
if(jt9com_.nutc < m_nutc0) m_RxLog |= 1; //Date and Time to all.txt
m_nutc0=jt9com_.nutc;
jt9com_.ntxmode=9;
if(m_modeTx=="JT65") jt9com_.ntxmode=65;
jt9com_.nmode=9;
if(m_mode=="JT65") jt9com_.nmode=65;
if(m_mode=="JT9+JT65") jt9com_.nmode=9+65;
jt9com_.ntrperiod=m_TRperiod;
m_nsave=0;
if(m_saveDecoded) m_nsave=2;
jt9com_.nsave=m_nsave;
strncpy(jt9com_.datetime, m_dateTime.toLatin1(), 20);
//newdat=1 ==> this is new data, must do the big FFT
//nagain=1 ==> decode only at fQSO +/- Tol
char *to = (char*)mem_jt9->data();
char *from = (char*) jt9com_.ss;
int size=sizeof(jt9com_);
if(jt9com_.newdat==0) {
int noffset = 4*184*NSMAX + 4*NSMAX + 2*NTMAX*12000;
to += noffset;
from += noffset;
size -= noffset;
}
memcpy(to, from, qMin(mem_jt9->size(), size));
QFile lockFile(m_appDir + "/.lock"); // Allow jt9 to start
lockFile.remove();
decodeBusy(true);
}
void MainWindow::jt9_error() //jt9_error
{
if(!m_killAll) {
msgBox("Error starting or running\n" + m_appDir + "/jt9 -s");
exit(1);
}
}
void MainWindow::readFromStderr() //readFromStderr
{
QByteArray t=proc_jt9.readAllStandardError();
msgBox(t);
}
void MainWindow::readFromStdout() //readFromStdout
{
while(proc_jt9.canReadLine()) {
QByteArray t=proc_jt9.readLine();
if(t.indexOf("<DecodeFinished>") >= 0) {
m_bdecoded = (t.mid(23,1).toInt()==1);
bool keepFile=m_saveAll or (m_saveDecoded and m_bdecoded);
if(!keepFile and !m_diskData) killFileTimer->start(45*1000); //Kill in 45 s
jt9com_.nagain=0;
jt9com_.ndiskdat=0;
QFile lockFile(m_appDir + "/.lock");
lockFile.open(QIODevice::ReadWrite);
ui->DecodeButton->setStyleSheet("");
decodeBusy(false);
m_RxLog=0;
m_startAnother=m_loopall;
m_blankLine=true;
return;
} else {
QFile f("ALL.TXT");
f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append);
QTextStream out(&f);
if(m_RxLog && 1) {
out << QDateTime::currentDateTimeUtc().toString("yyyy-MMM-dd hh:mm")
<< " " << m_dialFreq << " MHz " << m_mode << endl;
m_RxLog=0;
}
int n=t.length();
out << t.mid(0,n-2) << endl;
f.close();
QTextCursor cursor;
QTextBlockFormat bf;
if(m_insertBlank and m_blankLine and jt9com_.nagain==0) {
QString bg="#d3d3d3";
bf.setBackground(QBrush(QColor(bg)));
QString tt="----------------------------------------";
QString s = "<table border=0 cellspacing=0 width=100%><tr><td bgcolor=\"" +
bg + "\"><pre>" + tt + "</pre></td></tr></table>";
cursor = ui->decodedTextBrowser->textCursor();
cursor.movePosition(QTextCursor::End);
bf = cursor.blockFormat();
bf.setBackground(QBrush(QColor(bg)));
cursor.insertHtml(s);
m_blankLine=false;
}
QString bg="white";
if(t.indexOf(" CQ ")>0) bg="#66ff66"; //green
if(m_myCall!="" and t.indexOf(" "+m_myCall+" ")>0) bg="#ff6666"; //red
bool bQSO=abs(t.mid(14,4).toInt() - m_wideGraph->rxFreq()) <= 10;
QString t1=t.replace("\n","").mid(0,t.length()-4);
// if enabled add the DXCC entity and B4 status to the end of the preformated text line t1
int cqi = t.indexOf(" CQ ");
if (m_displayDXCCEntity && (cqi >= 0))
{
// extract the CQer's call TODO: does this work with all call formats? What about 'CQ DX'?
int s1 = 4 + t.indexOf(" CQ ");
int s2 = t.indexOf(" ",s1);
QString call = t.mid(s1,s2-s1);
QString countryName;
bool callWorkedBefore;
bool countryWorkedBefore;
m_logBook.match(/*in*/call,/*out*/countryName,callWorkedBefore,countryWorkedBefore);
//TODO this should happen on a resizeEvent
int charsAvail = m_logBook.getMaxDisplayedCharacters(ui->decodedTextBrowser->width());
// the decoder (seems) to always generate 40 chars. For a normal CQ call, the last five are spaces
t1 = t1.left(36); // reduce trailing white space
charsAvail -= 36;
if (!countryWorkedBefore) // therefore not worked call either
{
t1 += "!";
bg = "#66ff66"; // strong green
}
else
if (!callWorkedBefore) // but have worked the country
{
t1 += "~";
bg = "#76cd76"; // mid green
}
else
{
t1 += " "; // have worked this call before
bg="#9cc79c"; // pale green
}
charsAvail -= 1;
if (countryName.length()>charsAvail)
countryName = countryName.left(1)+"."+countryName.right(charsAvail-2); //abreviate the first word to the first letter, show remaining right most chars
t1 += countryName;
}
QString s = "<table border=0 cellspacing=0 width=100%><tr><td bgcolor=\"" +
bg + "\"><pre>" + t1 + "</pre></td></tr></table>";
bool b65=t1.indexOf("#")==19;
if(bQSO) {
cursor = ui->decodedTextBrowser2->textCursor();
cursor.movePosition(QTextCursor::End);
bf = cursor.blockFormat();
bf.setBackground(QBrush(QColor(bg)));
cursor.insertHtml(s);
ui->decodedTextBrowser2->setTextCursor(cursor);
m_QSOmsg=t1;
if(b65 and m_modeTx!="JT65") on_pbTxMode_clicked();
if(!b65 and m_modeTx=="JT65") on_pbTxMode_clicked();
}
if(jt9com_.nagain==0) {
if(m_myCall!="" and t.indexOf(" "+m_myCall+" ")>0) bg="#ff6666"; //red
QString s = "<table border=0 cellspacing=0 width=100%><tr><td bgcolor=\"" +
bg + "\"><pre>" + t1 + "</pre></td></tr></table>";
cursor = ui->decodedTextBrowser->textCursor();
cursor.movePosition(QTextCursor::End);
bf = cursor.blockFormat();
bf.setBackground(QBrush(QColor(bg)));
cursor.insertHtml(s);
ui->decodedTextBrowser->setTextCursor(cursor);
}
QString msg=t.mid(21);
int i1=msg.indexOf("\r");
if(i1>0) msg=msg.mid(0,i1-1) + " ";
bool b=stdmsg_(msg.mid(0,22).toLatin1().constData(),22);
QStringList w=msg.split(" ",QString::SkipEmptyParts);
if(b and w[0]==m_myCall) {
QString tt="";
if(w.length()>=3) tt=w[2];
bool ok;
i1=tt.toInt(&ok);
if(ok and i1>=-50 and i1<50) {
m_rptRcvd=tt;
} else {
if(tt.mid(0,1)=="R") {
i1=tt.mid(1).toInt(&ok);
if(ok and i1>=-50 and i1<50) {
m_rptRcvd=tt.mid(1);
}
}
}
}
int nsec=QDateTime::currentMSecsSinceEpoch()/1000-m_secBandChanged;
bool okToPost=(nsec>50);
QString msgmode="JT9";
if(b65) msgmode="JT65";
i1=msg.indexOf(" ");
QString c2=msg.mid(i1+1);
int i2=c2.indexOf(" ");
QString g2=c2.mid(i2+1,4);
c2=c2.mid(0,i2);
QString remote="call," + c2 + ",";
if(gridOK(g2)) remote += "gridsquare," + g2 + ",";
int nHz=t.mid(14,4).toInt();
uint nfreq=1000000.0*m_dialFreq + nHz + 0.5;
remote += "freq," + QString::number(nfreq);
int nsnr=t.mid(5,3).toInt();
remote += ",mode," + msgmode + ",snr," + QString::number(nsnr) + ",,";
wchar_t tremote[256];
remote.toWCharArray(tremote);
if(m_pskReporter and b and !m_diskData and okToPost) {
psk_Reporter->setLocalStation(m_myCall, m_myGrid, m_antDescription[m_band], "WSJT-X r" + rev.mid(6,4) );
QString freq = QString::number(nfreq);
QString snr= QString::number(nsnr);
if(gridOK(g2)) {
psk_Reporter->addRemoteStation(c2,g2,freq,msgmode,snr,
QString::number(QDateTime::currentDateTime().toTime_t()));
}
}
}
}
}
void MainWindow::killFile()
{
if(m_fname==m_fileToSave) {
} else {
QFile savedFile(m_fname);
savedFile.remove();
}
}
void MainWindow::on_EraseButton_clicked() //Erase
{
qint64 ms=QDateTime::currentMSecsSinceEpoch();
ui->decodedTextBrowser2->clear();
m_QSOmsg="";
if((ms-m_msErase)<500) {
ui->decodedTextBrowser->clear();
QFile f(m_appDir + "/decoded.txt");
if(f.exists()) f.remove();
}
m_msErase=ms;
}
void MainWindow::decodeBusy(bool b) //decodeBusy()
{
m_decoderBusy=b;
ui->DecodeButton->setEnabled(!b);
ui->actionOpen->setEnabled(!b);
ui->actionOpen_next_in_directory->setEnabled(!b);
ui->actionDecode_remaining_files_in_directory->setEnabled(!b);
}
//------------------------------------------------------------- //guiUpdate()
void MainWindow::guiUpdate()
{
static int iptt0=0;
static bool btxok0=false;
static char message[29];
static char msgsent[29];
static int nsendingsh=0;
static int giptt00=-1;
static int gcomport00=-1;
static double onAirFreq0=0.0;
int ret=0;
QString rt;
double tx1=0.0;
double tx2=1.0 + 85.0*m_nsps/12000.0 + icw[0]*2560.0/48000.0;
if(m_modeTx=="JT65") tx2=1.0 + 126*4096/11025.0 + icw[0]*2560.0/48000.0;
if(!m_txFirst) {
tx1 += m_TRperiod;
tx2 += m_TRperiod;
}
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
int nsec=ms/1000;
double tsec=0.001*ms;
double t2p=fmod(tsec,2*m_TRperiod);
bool bTxTime = ((t2p >= tx1) and (t2p < tx2)) or m_tune;
if(m_auto or m_tune) {
QFile f("txboth");
if(f.exists() and fmod(tsec,m_TRperiod) < (1.0 + 85.0*m_nsps/12000.0)) {
bTxTime=true;
}
double onAirFreq=m_dialFreq+1.e-6*m_txFreq;
if(onAirFreq>10.139900 and onAirFreq<10.140320) {
bTxTime=false;
if(m_tune) on_tuneButton_clicked();
if(onAirFreq!=onAirFreq0) {
onAirFreq0=onAirFreq;
on_autoButton_clicked();
QString t="Please choose another Tx frequency.\n";
t+="WSJT-X will not knowingly transmit\n";
t+="in the WSPR sub-band on 30 m.";
msgBox0.setText(t);
msgBox0.show();
}
}
float fTR=float((nsec%m_TRperiod))/m_TRperiod;
if(g_iptt==0 and ((bTxTime and !m_btxMute and fTR<0.4) or m_tune )) {
icw[0]=m_ncw;
//Raise PTT
if(m_catEnabled and m_bRigOpen and m_pttMethodIndex==0) {
g_iptt=1;
if(m_pttData) ret=rig->setPTT(RIG_PTT_ON_DATA, RIG_VFO_CURR);
if(!m_pttData) ret=rig->setPTT(RIG_PTT_ON_MIC, RIG_VFO_CURR);
if(ret!=RIG_OK) {
rt.sprintf("CAT control PTT failed: %d",ret);
msgBox(rt);
}
}
if(m_pttMethodIndex==1 or m_pttMethodIndex==2) { //DTR or RTS
ptt(m_pttPort,1,&g_iptt,&g_COMportOpen);
}
if(m_pttMethodIndex==3) { //VOX
g_iptt=1;
}
ptt1Timer->start(200); //Sequencer delay
}
if(!bTxTime || m_btxMute) {
m_btxok=false;
Q_EMIT muteAudioOutput ();
}
}
// Calculate Tx tones when needed
if((g_iptt==1 && iptt0==0) || m_restart) {
QByteArray ba;
if(m_ntx == 1) ba=ui->tx1->text().toLocal8Bit();
if(m_ntx == 2) ba=ui->tx2->text().toLocal8Bit();
if(m_ntx == 3) ba=ui->tx3->text().toLocal8Bit();
if(m_ntx == 4) ba=ui->tx4->text().toLocal8Bit();
if(m_ntx == 5) ba=ui->tx5->text().toLocal8Bit();
if(m_ntx == 6) ba=ui->tx6->text().toLocal8Bit();
if(m_ntx == 7) ba=ui->genMsg->text().toLocal8Bit();
if(m_ntx == 8) ba=ui->freeTextMsg->text().toLocal8Bit();
ba2msg(ba,message);
// ba2msg(ba,msgsent);
int len1=22;
int ichk=0,itext=0;
if(m_modeTx=="JT9") genjt9_(message,&ichk,msgsent,itone,&itext,len1,len1);
if(m_modeTx=="JT65") gen65_(message,&ichk,msgsent,itone,&itext,len1,len1);
msgsent[22]=0;
QString t=QString::fromLatin1(msgsent);
if(m_tune) t="TUNE";
lab3->setText("Last Tx: " + t);
if(m_restart) {
QFile f("ALL.TXT");
f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append);
QTextStream out(&f);
out << QDateTime::currentDateTimeUtc().toString("hhmm")
<< " Transmitting " << m_dialFreq << " MHz " << m_modeTx
<< ": " << t << endl;
f.close();
if(m_tx2QSO) displayTxMsg(t);
}
QStringList w=t.split(" ",QString::SkipEmptyParts);
t="";
if(w.length()==3) t=w[2];
icw[0]=0;
m_sent73=(t=="73" or itext!=0);
if(m_sent73) {
if(m_After73) icw[0]=m_ncw;
if(m_promptToLog and !m_tune) logQSOTimer->start(200);
}
if(m_idInt>0) {
int nmin=(m_sec0-m_secID)/60;
if(nmin >= m_idInt) {
icw[0]=m_ncw;
m_secID=m_sec0;
}
}
QString t2=QDateTime::currentDateTimeUtc().toString("hhmm");
if(itext==0 and w.length()>=3 and w[1]==m_myCall) {
int i1;
bool ok;
i1=t.toInt(&ok);
if(ok and i1>=-50 and i1<50) {
m_rptSent=t;
m_qsoStart=t2;
} else {
if(t.mid(0,1)=="R") {
i1=t.mid(1).toInt(&ok);
if(ok and i1>=-50 and i1<50) {
m_rptSent=t.mid(1);
m_qsoStart=t2;
}
}
}
}
if(itext==1 or (w.length()==3 and w[2]=="73")) m_qsoStop=t2;
m_restart=false;
}
// If PTT was just raised, start a countdown for raising TxOK:
// NB: could be better implemented with a timer
if(g_iptt == 1 && iptt0 == 0) {
nc1=-9; // TxDelay = 0.8 s
}
if(nc1 <= 0) {
nc1++;
}
if(nc1 == 0) {
QString t=QString::fromLatin1(msgsent);
if(t==m_msgSent0) {
m_repeatMsg++;
} else {
m_repeatMsg=0;
m_msgSent0=t;
}
signalMeter->setValue(0);
m_monitoring=false;
m_detector.setMonitoring(false);
m_btxok=true;
Q_EMIT muteAudioOutput (false);
m_transmitting=true;
ui->pbTxMode->setEnabled(false);
if(!m_tune) {
QFile f("ALL.TXT");
f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append);
QTextStream out(&f);
out << QDateTime::currentDateTimeUtc().toString("hhmm")
<< " Transmitting " << m_dialFreq << " MHz " << m_modeTx
<< ": " << t << endl;
f.close();
}
if(m_tx2QSO and !m_tune) displayTxMsg(t);
}
if(!m_btxok && btxok0 && g_iptt==1) stopTx();
/*
// If m_btxok was just lowered, start a countdown for lowering PTT
if(!m_btxok && btxok0 && g_iptt==1) nc0=-11; //RxDelay = 1.0 s
if(nc0 <= 0) {
nc0++;
}
*/
if(m_monitoring) {
ui->monitorButton->setStyleSheet(m_pbmonitor_style);
} else {
ui->monitorButton->setStyleSheet("");
}
if(m_startAnother) {
m_startAnother=false;
on_actionOpen_next_in_directory_triggered();
}
if(m_catEnabled and !m_bRigOpen) {
rigOpen();
if(m_bSplit or m_bXIT) setXIT(m_txFreq);
if(m_bRigOpen and !m_bSplit) {
int ret=rig->setSplitFreq(MHz(m_dialFreq),RIG_VFO_B);
if(ret!=RIG_OK) {
QString rt;
rt.sprintf("Setting VFO_B failed: %d",ret);
msgBox(rt);
}
}
}
if(nsec != m_sec0) { //Once per second
QDateTime t = QDateTime::currentDateTimeUtc();
if(m_transmitting) {
if(nsendingsh==1) {
lab1->setStyleSheet("QLabel{background-color: #66ffff}");
} else if(nsendingsh==-1) {
lab1->setStyleSheet("QLabel{background-color: #ffccff}");
} else {
lab1->setStyleSheet("QLabel{background-color: #ffff33}");
}
if(m_tune) {
lab1->setText("Tx: TUNE");
} else {
char s[37];
sprintf(s,"Tx: %s",msgsent);
lab1->setText(s);
}
} else if(m_monitoring) {
lab1->setStyleSheet("QLabel{background-color: #00ff00}");
lab1->setText("Receiving ");
} else if (!m_diskData) {
lab1->setStyleSheet("");
lab1->setText("");
}
m_setftx=0;
QString utc = t.date().toString("yyyy MMM dd") + "\n " +
t.time().toString() + " ";
ui->labUTC->setText(utc);
if(!m_monitoring and !m_diskData) {
signalMeter->setValue(0);
}
if(m_catEnabled and m_poll>0 and (nsec%m_poll)==0 and
!m_decoderBusy) pollRigFreq();
m_sec0=nsec;
}
if(g_iptt!=giptt00 or g_COMportOpen!=gcomport00) {
giptt00=g_iptt;
gcomport00=g_COMportOpen;
}
iptt0=g_iptt;
btxok0=m_btxok;
} //End of GUIupdate
void MainWindow::displayTxMsg(QString t)
{
QString bg="yellow";
QTextBlockFormat bf;
QTextCursor cursor;
QString t1=" @ ";
if(m_modeTx=="JT65") t1=" # ";
QString t2;
t2.sprintf("%4d",m_txFreq);
t=QDateTime::currentDateTimeUtc().toString("hhmm") + \
" Tx " + t2 + t1 + t;
QString s = "<table border=0 cellspacing=0 width=100%><tr><td bgcolor=\"" +
bg + "\"><pre>" + t + "</pre></td></tr></table>";
cursor = ui->decodedTextBrowser2->textCursor();
cursor.movePosition(QTextCursor::End);
bf = cursor.blockFormat();
bf.setBackground(QBrush(QColor(bg)));
cursor.insertHtml(s);
ui->decodedTextBrowser2->setTextCursor(cursor);
}
void MainWindow::startTx2()
{
if (!m_modulator.isActive ()) {
QString t=ui->tx6->text();
double snr=t.mid(1,5).toDouble();
if(snr>0.0 or snr < -50.0) snr=99.0;
transmit (snr);
signalMeter->setValue(0);
m_monitoring=false;
m_detector.setMonitoring(false);
m_btxok=true;
Q_EMIT muteAudioOutput (false);
m_transmitting=true;
ui->pbTxMode->setEnabled(false);
}
}
void MainWindow::stopTx()
{
Q_EMIT endTransmitMessage ();
Q_EMIT stopAudioOutputStream ();
m_transmitting=false;
ui->pbTxMode->setEnabled(true);
g_iptt=0;
lab1->setStyleSheet("");
lab1->setText("");
ptt0Timer->start(200); //Sequencer delay
m_monitoring=true;
m_detector.setMonitoring(true);
}
void MainWindow::stopTx2()
{
int ret=0;
QString rt;
//Lower PTT
if(m_catEnabled and m_bRigOpen and m_pttMethodIndex==0) {
ret=rig->setPTT(RIG_PTT_OFF, RIG_VFO_CURR); //CAT control for PTT=0
if(ret!=RIG_OK) {
rt.sprintf("CAT control PTT failed: %d",ret);
msgBox(rt);
}
}
if(m_pttMethodIndex==1 or m_pttMethodIndex==2) {
ptt(m_pttPort,0,&g_iptt,&g_COMportOpen);
}
if(m_73TxDisable and m_sent73) on_stopTxButton_clicked();
if(m_runaway and m_repeatMsg>m_watchdogLimit) {
on_stopTxButton_clicked();
msgBox0.setText("Runaway Tx watchdog");
msgBox0.show();
m_repeatMsg=0;
}
}
void MainWindow::ba2msg(QByteArray ba, char message[]) //ba2msg()
{
int iz=ba.length();
for(int i=0;i<22; i++) {
if(i<iz) {
message[i]=ba[i];
} else {
message[i]=32;
}
}
message[22]=0;
}
void MainWindow::on_txFirstCheckBox_stateChanged(int nstate) //TxFirst
{
m_txFirst = (nstate==2);
}
void MainWindow::set_ntx(int n) //set_ntx()
{
m_ntx=n;
}
void MainWindow::on_txb1_clicked() //txb1
{
m_ntx=1;
ui->txrb1->setChecked(true);
m_restart=true;
}
void MainWindow::on_txb2_clicked() //txb2
{
m_ntx=2;
ui->txrb2->setChecked(true);
m_restart=true;
}
void MainWindow::on_txb3_clicked() //txb3
{
m_ntx=3;
ui->txrb3->setChecked(true);
m_restart=true;
}
void MainWindow::on_txb4_clicked() //txb4
{
m_ntx=4;
ui->txrb4->setChecked(true);
m_restart=true;
}
void MainWindow::on_txb5_clicked() //txb5
{
m_ntx=5;
ui->txrb5->setChecked(true);
m_restart=true;
}
void MainWindow::on_txb6_clicked() //txb6
{
m_ntx=6;
ui->txrb6->setChecked(true);
m_restart=true;
}
void MainWindow::doubleClickOnCall2(bool shift, bool ctrl)
{
m_decodedText2=true;
doubleClickOnCall(shift,ctrl);
m_decodedText2=false;
}
void MainWindow::doubleClickOnCall(bool shift, bool ctrl)
{
QTextCursor cursor;
if(!m_decodedText2) cursor=ui->decodedTextBrowser2->textCursor();
if(m_decodedText2) cursor=ui->decodedTextBrowser->textCursor();
cursor.select(QTextCursor::LineUnderCursor);
int i2=cursor.position();
if(shift and i2==-9999) return; //Silence compiler warning
QString t;
if(!m_decodedText2) t= ui->decodedTextBrowser2->toPlainText(); //Full contents
if(m_decodedText2) t= ui->decodedTextBrowser->toPlainText();
QString t1 = t.mid(0,i2); //contents up to \n on selected line
int i1=t1.lastIndexOf("\n") + 1; //points to first char of line
QString t2 = t1.mid(i1,i2-i1); //selected line
// if(t2.indexOf("Tx")==6) return; //Ignore Tx line
int i4=t.mid(i1).length();
if(i4>55) i4=55;
QString t3=t.mid(i1,i4);
int i5=t3.indexOf(" CQ DX ");
if(i5>0) t3=t3.mid(0,i5+3) + "_" + t3.mid(i5+4); //Make it "CQ_DX" (one word)
QStringList t4=t3.split(" ",QString::SkipEmptyParts);
if(t4.length() <5) return; //Skip the rest if no decoded text
int i9=m_QSOmsg.indexOf(t2);
if(i9<0 and t2.indexOf("Tx")==-1) {
QString bg="white";
if(t2.indexOf(" CQ ")>0) bg="#66ff66"; //green
if(m_myCall!="" and t2.indexOf(" "+m_myCall+" ")>0) bg="#ff6666"; //red
QTextBlockFormat bf;
QString s = "<table border=0 cellspacing=0 width=100%><tr><td bgcolor=\"" +
bg + "\"><pre>" + t2 + "</pre></td></tr></table>";
cursor = ui->decodedTextBrowser2->textCursor();
cursor.movePosition(QTextCursor::End);
bf = cursor.blockFormat();
bf.setBackground(QBrush(QColor(bg)));
cursor.insertHtml(s);
ui->decodedTextBrowser2->setTextCursor(cursor);
m_QSOmsg=t2;
}
int nfreq=t4.at(3).toInt();
if(t4.at(1)=="Tx") nfreq=t4.at(2).toInt();
m_wideGraph->setRxFreq(nfreq); //Set Rx freq
if(t4.at(1)=="Tx") {
if(ctrl) ui->TxFreqSpinBox->setValue(nfreq); //Set Tx freq
return;
}
if(t4.at(4)=="@") {
m_modeTx="JT9";
ui->pbTxMode->setText("Tx JT9 @");
m_wideGraph->setModeTx(m_modeTx);
}
if(t4.at(4)=="#") {
m_modeTx="JT65";
ui->pbTxMode->setText("Tx JT65 #");
m_wideGraph->setModeTx(m_modeTx);
}
QString firstcall=t4.at(5);
// Don't change Tx freq if a station is calling me, unless m_lockTxFreq
// is true or CTRL is held down or
if((firstcall!=m_myCall) or m_lockTxFreq or ctrl) {
ui->TxFreqSpinBox->setValue(nfreq);
}
QString hiscall=t4.at(6);
QString hisgrid="";
if(t4.length()>=8) hisgrid=t4.at(7);
if(hiscall!=ui->dxCallEntry->text()) ui->dxGridEntry->setText("");
ui->dxCallEntry->setText(hiscall);
if(gridOK(hisgrid)) ui->dxGridEntry->setText(hisgrid);
if(ui->dxGridEntry->text()=="") lookup();
m_hisGrid=ui->dxGridEntry->text();
int n = 60*t2.mid(0,2).toInt() + t2.mid(2,2).toInt();
int nmod=n%(m_TRperiod/30);
m_txFirst=(nmod!=0);
ui->txFirstCheckBox->setChecked(m_txFirst);
QString rpt=t4.at(1);
if(rpt.indexOf(" ")==0) rpt="+" + rpt.mid(2,2);
if(rpt.indexOf(" -")==0) rpt=rpt.mid(1,2);
if(rpt.indexOf(" ")==0) rpt="+" + rpt.mid(1,2);
int nr=rpt.toInt();
if(nr<-50) rpt="-50";
if(nr>49) rpt="+49";
if(nr>=-9 and nr<=-1) rpt="-0" + rpt.mid(1);
if(nr>=0 and nr<=9) rpt="+0" + rpt;
if(nr>=10) rpt="+" + rpt;
ui->rptSpinBox->setValue(rpt.toInt());
genStdMsgs(rpt);
if(t2.indexOf(m_myCall)>=0) {
if(t4.length()>=7 and !gridOK(t4.at(7))) {
QString r=t4.at(7);
if(r.mid(0,3)=="RRR") {
m_ntx=5;
ui->txrb5->setChecked(true);
if(ui->tabWidget->currentIndex()==1) {
ui->genMsg->setText(ui->tx5->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
}
} else if(r.mid(0,1)=="R") {
m_ntx=4;
ui->txrb4->setChecked(true);
if(ui->tabWidget->currentIndex()==1) {
ui->genMsg->setText(ui->tx4->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
}
} else if(r.toInt()>=-50 and r.toInt()<=49) {
m_ntx=3;
ui->txrb3->setChecked(true);
if(ui->tabWidget->currentIndex()==1) {
ui->genMsg->setText(ui->tx3->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
}
} else if(r.toInt()==73) {
m_ntx=5;
ui->txrb5->setChecked(true);
if(ui->tabWidget->currentIndex()==1) {
ui->genMsg->setText(ui->tx5->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
}
}
} else {
m_ntx=2;
ui->txrb2->setChecked(true);
if(ui->tabWidget->currentIndex()==1) {
ui->genMsg->setText(ui->tx2->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
}
}
} else {
m_ntx=1;
ui->txrb1->setChecked(true);
if(ui->tabWidget->currentIndex()==1) {
ui->genMsg->setText(ui->tx1->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
}
}
if(m_quickCall) {
m_auto=true;
ui->autoButton->setStyleSheet(m_pbAutoOn_style);
}
}
void MainWindow::genStdMsgs(QString rpt) //genStdMsgs()
{
QString t;
QString hisCall=ui->dxCallEntry->text().toUpper().trimmed();
ui->dxCallEntry->setText(hisCall);
if(hisCall=="") {
ui->labAz->setText("");
ui->labDist->setText("");
ui->tx1->setText("");
ui->tx2->setText("");
ui->tx3->setText("");
ui->tx4->setText("");
ui->tx5->setText("");
ui->tx6->setText("");
if(m_myCall!="" and m_myGrid!="") {
t="CQ " + m_myCall + " " + m_myGrid.mid(0,4);
msgtype(t, ui->tx6);
}
ui->genMsg->setText("");
ui->freeTextMsg->setText("");
return;
}
QString hisBase=baseCall(hisCall);
QString myBase=baseCall(m_myCall);
QString t0=hisBase + " " + myBase + " ";
t=t0 + m_myGrid.mid(0,4);
if(myBase!=m_myCall) t="DE " + m_myCall + " " + m_myGrid.mid(0,4);
msgtype(t, ui->tx1);
if(rpt == "") {
t=t+" OOO";
msgtype(t, ui->tx2);
msgtype("RO", ui->tx3);
msgtype("RRR", ui->tx4);
msgtype("73", ui->tx5);
} else {
t=t0 + rpt;
msgtype(t, ui->tx2);
t=t0 + "R" + rpt;
msgtype(t, ui->tx3);
t=t0 + "RRR";
msgtype(t, ui->tx4);
t=t0 + "73";
if(myBase!=m_myCall) t="DE " + m_myCall + " 73";
msgtype(t, ui->tx5);
}
t="CQ " + m_myCall + " " + m_myGrid.mid(0,4);
msgtype(t, ui->tx6);
m_ntx=1;
ui->txrb1->setChecked(true);
m_rpt=rpt;
}
QString MainWindow::baseCall(QString t)
{
int n1=t.indexOf("/");
if(n1<0) return t;
int n2=t.length()-n1-1;
if(n2>=n1) return t.mid(n1+1);
return t.mid(0,n1);
}
void MainWindow::lookup() //lookup()
{
QString hisCall=ui->dxCallEntry->text().toUpper().trimmed();
ui->dxCallEntry->setText(hisCall);
QString call3File = m_appDir + "/CALL3.TXT";
QFile f(call3File);
if(!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
msgBox("Cannot open " + call3File);
return;
}
char c[132];
qint64 n=0;
for(int i=0; i<999999; i++) {
n=f.readLine(c,sizeof(c));
if(n <= 0) {
ui->dxGridEntry->setText("");
break;
}
QString t=QString(c);
if(t.indexOf(hisCall)==0) {
int i1=t.indexOf(",");
QString hisgrid=t.mid(i1+1,6);
i1=hisgrid.indexOf(",");
if(i1>0) {
hisgrid=hisgrid.mid(0,4);
} else {
hisgrid=hisgrid.mid(0,4) + hisgrid.mid(4,2).toLower();
}
ui->dxGridEntry->setText(hisgrid);
break;
}
}
f.close();
}
void MainWindow::on_lookupButton_clicked() //Lookup button
{
lookup();
}
void MainWindow::on_addButton_clicked() //Add button
{
if(ui->dxGridEntry->text()=="") {
msgBox("Please enter a valid grid locator.");
return;
}
m_call3Modified=false;
QString hisCall=ui->dxCallEntry->text().toUpper().trimmed();
QString hisgrid=ui->dxGridEntry->text().trimmed();
QString newEntry=hisCall + "," + hisgrid;
// int ret = QMessageBox::warning(this, "Add",
// newEntry + "\n" + "Is this station known to be active on EME?",
// QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
// if(ret==QMessageBox::Yes) {
// newEntry += ",EME,,";
// } else {
newEntry += ",,,";
// }
QString call3File = m_appDir + "/CALL3.TXT";
QFile f1(call3File);
if(!f1.open(QIODevice::ReadOnly | QIODevice::Text)) {
msgBox("Cannot open " + call3File);
return;
}
if(f1.size()==0) {
f1.close();
f1.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream out(&f1);
out << "ZZZZZZ" << endl;
f1.close();
f1.open(QIODevice::ReadOnly | QIODevice::Text);
}
QString tmpFile = m_appDir + "/CALL3.TMP";
QFile f2(tmpFile);
if(!f2.open(QIODevice::WriteOnly | QIODevice::Text)) {
msgBox("Cannot open " + tmpFile);
return;
}
QTextStream in(&f1);
QTextStream out(&f2);
QString hc=hisCall;
QString hc1="";
QString hc2="AAAAAA";
QString s;
do {
s=in.readLine();
hc1=hc2;
if(s.mid(0,2)=="//") {
out << s + "\n";
} else {
int i1=s.indexOf(",");
hc2=s.mid(0,i1);
if(hc>hc1 && hc<hc2) {
out << newEntry + "\n";
if(s.mid(0,6)=="ZZZZZZ") {
out << s + "\n";
// exit; //Statement has no effect!
}
m_call3Modified=true;
} else if(hc==hc2) {
QString t=s + "\n\n is already in CALL3.TXT\n" +
"Do you wish to replace it?";
int ret = QMessageBox::warning(this, "Add",t,
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if(ret==QMessageBox::Yes) {
out << newEntry + "\n";
m_call3Modified=true;
}
} else {
if(s!="") out << s + "\n";
}
}
} while(!s.isNull());
f1.close();
if(hc>hc1 && !m_call3Modified) {
out << newEntry + "\n";
}
if(m_call3Modified) {
QFile f0(m_appDir + "/CALL3.OLD");
if(f0.exists()) f0.remove();
QFile f1(m_appDir + "/CALL3.TXT");
f1.rename(m_appDir + "/CALL3.OLD");
f2.rename(m_appDir + "/CALL3.TXT");
f2.close();
}
}
void MainWindow::msgtype(QString t, QLineEdit* tx) //msgtype()
{
char message[23];
char msgsent[23];
int len1=22;
t=t.toUpper();
QByteArray s=t.toUpper().toLocal8Bit();
ba2msg(s,message);
int ichk=1,itext=0;
genjt9_(message,&ichk,msgsent,itone,&itext,len1,len1);
msgsent[22]=0;
bool text=false;
if(itext!=0) text=true;
QString t1;
t1.fromLatin1(msgsent);
if(text) t1=t1.mid(0,13);
QPalette p(tx->palette());
if(text) {
p.setColor(QPalette::Base,"#ffccff");
} else {
p.setColor(QPalette::Base,Qt::white);
}
tx->setPalette(p);
int len=t.length();
if(text) {
len=qMin(len,13);
tx->setText(t.mid(0,len).toUpper());
} else {
tx->setText(t);
}
}
void MainWindow::on_tx1_editingFinished() //tx1 edited
{
QString t=ui->tx1->text();
msgtype(t, ui->tx1);
}
void MainWindow::on_tx2_editingFinished() //tx2 edited
{
QString t=ui->tx2->text();
msgtype(t, ui->tx2);
}
void MainWindow::on_tx3_editingFinished() //tx3 edited
{
QString t=ui->tx3->text();
msgtype(t, ui->tx3);
}
void MainWindow::on_tx4_editingFinished() //tx4 edited
{
QString t=ui->tx4->text();
msgtype(t, ui->tx4);
}
void MainWindow::on_tx5_editingFinished() //tx5 edited
{
QString t=ui->tx5->text();
msgtype(t, ui->tx5);
}
void MainWindow::on_tx6_editingFinished() //tx6 edited
{
QString t=ui->tx6->text();
msgtype(t, ui->tx6);
// G4WJS: disabled setting of snr from msg 6 on live edit, will
// still generate noise on next full tx period
// double snr=t.mid(1,5).toDouble();
// if(snr>0.0 or snr < -50.0) snr=99.0;
// m_modulator.setTxSNR(snr);
}
void MainWindow::on_dxCallEntry_textChanged(const QString &t) //dxCall changed
{
m_hisCall=t.toUpper().trimmed();
ui->dxCallEntry->setText(m_hisCall);
statusChanged();
}
void MainWindow::on_dxGridEntry_textChanged(const QString &t) //dxGrid changed
{
int n=t.length();
if(n!=4 and n!=6) {
ui->labAz->setText("");
ui->labDist->setText("");
return;
}
if(!t[0].isLetter() or !t[1].isLetter()) return;
if(!t[2].isDigit() or !t[3].isDigit()) return;
if(n==4) m_hisGrid=t.mid(0,2).toUpper() + t.mid(2,2);
if(n==6) m_hisGrid=t.mid(0,2).toUpper() + t.mid(2,2) +
t.mid(4,2).toLower();
ui->dxGridEntry->setText(m_hisGrid);
if(gridOK(m_hisGrid)) {
qint64 nsec = QDateTime::currentMSecsSinceEpoch() % 86400;
double utch=nsec/3600.0;
int nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter;
azdist_(m_myGrid.toLatin1().data(),m_hisGrid.toLatin1().data(),&utch,
&nAz,&nEl,&nDmiles,&nDkm,&nHotAz,&nHotABetter,6,6);
QString t;
t.sprintf("Az: %d",nAz);
ui->labAz->setText(t);
if(m_bMiles) t.sprintf("%d mi",int(0.621371*nDkm));
if(!m_bMiles) t.sprintf("%d km",nDkm);
ui->labDist->setText(t);
} else {
ui->labAz->setText("");
ui->labDist->setText("");
}
}
void MainWindow::on_genStdMsgsPushButton_clicked() //genStdMsgs button
{
genStdMsgs(m_rpt);
}
void MainWindow::on_logQSOButton_clicked() //Log QSO button
{
if(m_hisCall=="") return;
m_dateTimeQSO=QDateTime::currentDateTimeUtc();
m_logDlg->initLogQSO(m_hisCall,m_hisGrid,m_modeTx,m_rptSent,m_rptRcvd,
m_dateTimeQSO,m_dialFreq+m_txFreq/1.0e6,
m_myCall,m_myGrid,m_noSuffix,m_toRTTY,m_dBtoComments);
}
void MainWindow::acceptQSO2(bool accepted)
{
if(accepted) {
m_logBook.addAsWorked(m_hisCall);
if(m_clearCallGrid) {
m_hisCall="";
ui->dxCallEntry->setText("");
m_hisGrid="";
ui->dxGridEntry->setText("");
m_rptSent="";
m_rptRcvd="";
m_qsoStart="";
m_qsoStop="";
}
}
}
void MainWindow::on_actionJT9_1_triggered()
{
m_mode="JT9";
if(m_modeTx!="JT9") on_pbTxMode_clicked();
statusChanged();
m_TRperiod=60;
m_nsps=6912;
m_hsymStop=173;
lab2->setStyleSheet("QLabel{background-color: #ff6ec7}");
lab2->setText(m_mode);
ui->actionJT9_1->setChecked(true);
m_wideGraph->setPeriod(m_TRperiod,m_nsps);
m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
ui->pbTxMode->setEnabled(false);
}
void MainWindow::on_actionJT65_triggered()
{
m_mode="JT65";
if(m_modeTx!="JT65") on_pbTxMode_clicked();
statusChanged();
m_TRperiod=60;
m_nsps=6912; //For symspec only
m_hsymStop=173;
lab2->setStyleSheet("QLabel{background-color: #ffff00}");
lab2->setText(m_mode);
ui->actionJT65->setChecked(true);
m_wideGraph->setPeriod(m_TRperiod,m_nsps);
m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
ui->pbTxMode->setEnabled(false);
}
void MainWindow::on_actionJT9_JT65_triggered()
{
m_mode="JT9+JT65";
// if(m_modeTx!="JT9") on_pbTxMode_clicked();
statusChanged();
m_TRperiod=60;
m_nsps=6912;
m_hsymStop=173;
lab2->setStyleSheet("QLabel{background-color: #ffa500}");
lab2->setText(m_mode);
ui->actionJT9_JT65->setChecked(true);
m_wideGraph->setPeriod(m_TRperiod,m_nsps);
m_wideGraph->setMode(m_mode);
m_wideGraph->setModeTx(m_modeTx);
ui->pbTxMode->setEnabled(true);
}
void MainWindow::on_TxFreqSpinBox_valueChanged(int n)
{
m_txFreq=n;
m_wideGraph->setTxFreq(n);
if(m_lockTxFreq) ui->RxFreqSpinBox->setValue(n);
Q_EMIT transmitFrequency (m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0));
}
void MainWindow::on_RxFreqSpinBox_valueChanged(int n)
{
m_rxFreq=n;
m_wideGraph->setRxFreq(n);
if(m_lockTxFreq) ui->TxFreqSpinBox->setValue(n);
}
void MainWindow::on_actionQuickDecode_triggered()
{
m_ndepth=1;
ui->actionQuickDecode->setChecked(true);
}
void MainWindow::on_actionMediumDecode_triggered()
{
m_ndepth=2;
ui->actionMediumDecode->setChecked(true);
}
void MainWindow::on_actionDeepestDecode_triggered()
{
m_ndepth=3;
ui->actionDeepestDecode->setChecked(true);
}
void MainWindow::on_inGain_valueChanged(int n)
{
m_inGain=n;
}
void MainWindow::on_actionMonitor_OFF_at_startup_triggered()
{
m_monitorStartOFF=!m_monitorStartOFF;
}
void MainWindow::on_actionErase_ALL_TXT_triggered() //Erase ALL.TXT
{
int ret = QMessageBox::warning(this, "Confirm Erase",
"Are you sure you want to erase file ALL.TXT ?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if(ret==QMessageBox::Yes) {
QFile f("ALL.TXT");
f.remove();
m_RxLog=1;
}
}
void MainWindow::on_actionErase_wsjtx_log_adi_triggered()
{
int ret = QMessageBox::warning(this, "Confirm Erase",
"Are you sure you want to erase file wsjtx_log.adi ?",
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if(ret==QMessageBox::Yes) {
QFile f("wsjtx_log.adi");
f.remove();
}
}
void MainWindow::showMacros(const QPoint &pos)
{
if(m_macro.length()<10) return;
QPoint globalPos = ui->tx5->mapToGlobal(pos);
QMenu popupMenu;
QAction* popup1 = new QAction(m_macro[0],ui->tx5);
QAction* popup2 = new QAction(m_macro[1],ui->tx5);
QAction* popup3 = new QAction(m_macro[2],ui->tx5);
QAction* popup4 = new QAction(m_macro[3],ui->tx5);
QAction* popup5 = new QAction(m_macro[4],ui->tx5);
QAction* popup6 = new QAction(m_macro[5],ui->tx5);
QAction* popup7 = new QAction(m_macro[6],ui->tx5);
QAction* popup8 = new QAction(m_macro[7],ui->tx5);
QAction* popup9 = new QAction(m_macro[8],ui->tx5);
QAction* popup10 = new QAction(m_macro[9],ui->tx5);
if(m_macro[0]!="") popupMenu.addAction(popup1);
if(m_macro[1]!="") popupMenu.addAction(popup2);
if(m_macro[2]!="") popupMenu.addAction(popup3);
if(m_macro[3]!="") popupMenu.addAction(popup4);
if(m_macro[4]!="") popupMenu.addAction(popup5);
if(m_macro[5]!="") popupMenu.addAction(popup6);
if(m_macro[6]!="") popupMenu.addAction(popup7);
if(m_macro[7]!="") popupMenu.addAction(popup8);
if(m_macro[8]!="") popupMenu.addAction(popup9);
if(m_macro[9]!="") popupMenu.addAction(popup10);
connect(popup1,SIGNAL(triggered()), this, SLOT(onPopup1()));
connect(popup2,SIGNAL(triggered()), this, SLOT(onPopup2()));
connect(popup3,SIGNAL(triggered()), this, SLOT(onPopup3()));
connect(popup4,SIGNAL(triggered()), this, SLOT(onPopup4()));
connect(popup5,SIGNAL(triggered()), this, SLOT(onPopup5()));
connect(popup6,SIGNAL(triggered()), this, SLOT(onPopup6()));
connect(popup7,SIGNAL(triggered()), this, SLOT(onPopup7()));
connect(popup8,SIGNAL(triggered()), this, SLOT(onPopup8()));
connect(popup9,SIGNAL(triggered()), this, SLOT(onPopup9()));
connect(popup10,SIGNAL(triggered()), this, SLOT(onPopup10()));
popupMenu.exec(globalPos);
}
void MainWindow::onPopup1() { ui->tx5->setText(m_macro[0]); freeText(); }
void MainWindow::onPopup2() { ui->tx5->setText(m_macro[1]); freeText(); }
void MainWindow::onPopup3() { ui->tx5->setText(m_macro[2]); freeText(); }
void MainWindow::onPopup4() { ui->tx5->setText(m_macro[3]); freeText(); }
void MainWindow::onPopup5() { ui->tx5->setText(m_macro[4]); freeText(); }
void MainWindow::onPopup6() { ui->tx5->setText(m_macro[5]); freeText(); }
void MainWindow::onPopup7() { ui->tx5->setText(m_macro[6]); freeText(); }
void MainWindow::onPopup8() { ui->tx5->setText(m_macro[7]); freeText(); }
void MainWindow::onPopup9() { ui->tx5->setText(m_macro[8]); freeText(); }
void MainWindow::onPopup10() { ui->tx5->setText(m_macro[9]); freeText(); }
void MainWindow::freeText() { ui->freeTextMsg->setText(ui->tx5->text()); }
bool MainWindow::gridOK(QString g)
{
bool b=g.mid(0,1).compare("A")>=0 and
g.mid(0,1).compare("R")<=0 and
g.mid(1,1).compare("A")>=0 and
g.mid(1,1).compare("R")<=0 and
g.mid(2,1).compare("0")>=0 and
g.mid(2,1).compare("9")<=0 and
g.mid(3,1).compare("0")>=0 and
g.mid(3,1).compare("9")<=0;
return b;
}
void MainWindow::on_actionConvert_JT9_x_to_RTTY_triggered(bool checked)
{
m_toRTTY=checked;
}
void MainWindow::on_actionLog_dB_reports_to_Comments_triggered(bool checked)
{
m_dBtoComments=checked;
}
void MainWindow::on_bandComboBox_activated(int index)
{
int ret=0;
QString rt;
m_band=index;
QString t=m_dFreq[index];
m_dialFreq=t.toDouble();
if(m_plus2kHz) m_dialFreq+=0.002;
dialFreqChanged2(m_dialFreq);
m_repeatMsg=0;
m_secBandChanged=QDateTime::currentMSecsSinceEpoch()/1000;
if(m_catEnabled) {
if(!m_bRigOpen) {
rigOpen();
}
if(m_bRigOpen) {
m_dontReadFreq=true;
ret=rig->setFreq(MHz(m_dialFreq));
if(m_bSplit or m_bXIT) setXIT(m_txFreq);
bumpFqso(11);
bumpFqso(12);
if(ret!=RIG_OK) {
rt.sprintf("Set rig frequency failed: %d",ret);
msgBox(rt);
}
}
}
QFile f2("ALL.TXT");
f2.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append);
QTextStream out(&f2);
out << QDateTime::currentDateTimeUtc().toString("yyyy-MMM-dd hh:mm")
<< " " << m_dialFreq << " MHz " << m_mode << endl;
f2.close();
psk_Reporter->setLocalStation(m_myCall, m_myGrid, m_antDescription[m_band], "WSJT-X r" + rev.mid(6,4) );
}
void MainWindow::on_actionPrompt_to_log_QSO_triggered(bool checked)
{
m_promptToLog=checked;
}
void MainWindow::on_actionBlank_line_between_decoding_periods_triggered(bool checked)
{
m_insertBlank=checked;
}
void MainWindow::on_actionEnable_DXCC_entity_triggered(bool checked)
{
m_displayDXCCEntity=checked;
if (checked)
m_logBook.init(); // re-read the log and cty.dat files
}
void MainWindow::on_actionClear_DX_Call_and_Grid_after_logging_triggered(bool checked)
{
m_clearCallGrid=checked;
}
void MainWindow::on_actionDisplay_distance_in_miles_triggered(bool checked)
{
m_bMiles=checked;
on_dxGridEntry_textChanged(m_hisGrid);
}
void MainWindow::on_pbCallCQ_clicked()
{
genStdMsgs(m_rpt);
ui->genMsg->setText(ui->tx6->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
if(m_transmitting) m_restart=true;
}
void MainWindow::on_pbAnswerCaller_clicked()
{
genStdMsgs(m_rpt);
ui->genMsg->setText(ui->tx2->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
if(m_transmitting) m_restart=true;
}
void MainWindow::on_pbSendRRR_clicked()
{
genStdMsgs(m_rpt);
ui->genMsg->setText(ui->tx4->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
if(m_transmitting) m_restart=true;
}
void MainWindow::on_pbAnswerCQ_clicked()
{
genStdMsgs(m_rpt);
ui->genMsg->setText(ui->tx1->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
if(m_transmitting) m_restart=true;
}
void MainWindow::on_pbSendReport_clicked()
{
genStdMsgs(m_rpt);
ui->genMsg->setText(ui->tx3->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
if(m_transmitting) m_restart=true;
}
void MainWindow::on_pbSend73_clicked()
{
genStdMsgs(m_rpt);
ui->genMsg->setText(ui->tx5->text());
m_ntx=7;
ui->rbGenMsg->setChecked(true);
if(m_transmitting) m_restart=true;
}
void MainWindow::on_rbGenMsg_toggled(bool checked)
{
m_freeText=!checked;
if(!m_freeText) {
m_ntx=7;
if(m_transmitting) m_restart=true;
}
}
void MainWindow::on_rbFreeText_toggled(bool checked)
{
m_freeText=checked;
if(m_freeText) {
m_ntx=8;
if (m_transmitting) m_restart=true;
}
}
void MainWindow::on_freeTextMsg_editingFinished()
{
QString t=ui->freeTextMsg->text();
msgtype(t, ui->freeTextMsg);
}
void MainWindow::on_actionDouble_click_on_call_sets_Tx_Enable_triggered(bool checked)
{
m_quickCall=checked;
}
void MainWindow::on_rptSpinBox_valueChanged(int n)
{
m_rpt=QString::number(n);
int ntx0=m_ntx;
QString t=ui->tx5->text();
genStdMsgs(m_rpt);
ui->tx5->setText(t);
m_ntx=ntx0;
if(m_ntx==1) ui->txrb1->setChecked(true);
if(m_ntx==2) ui->txrb2->setChecked(true);
if(m_ntx==3) ui->txrb3->setChecked(true);
if(m_ntx==4) ui->txrb4->setChecked(true);
if(m_ntx==5) ui->txrb5->setChecked(true);
if(m_ntx==6) ui->txrb6->setChecked(true);
statusChanged();
}
void MainWindow::on_action_73TxDisable_triggered(bool checked)
{
m_73TxDisable=checked;
}
void MainWindow::on_actionRunaway_Tx_watchdog_triggered(bool checked)
{
m_runaway=checked;
}
void MainWindow::on_tuneButton_clicked()
{
if(m_tune) {
nc1=1; //disable the countdown timer
tuneButtonTimer->start(250);
} else {
m_tune=true;
m_sent73=false;
Q_EMIT tune ();
m_repeatMsg=0;
ui->tuneButton->setStyleSheet(m_pbTune_style);
}
}
void MainWindow::on_stopTxButton_clicked() //Stop Tx
{
if(m_tune) {
m_tune=false;
Q_EMIT tune (m_tune);
}
if(m_auto) on_autoButton_clicked();
m_btxok=false;
Q_EMIT muteAudioOutput ();
m_repeatMsg=0;
ui->tuneButton->setStyleSheet("");
}
void MainWindow::rigOpen()
{
QString t;
int ret;
rig = new Rig();
if(m_rig<9900) {
if (!rig->init(m_rig)) {
msgBox("Rig init failure");
return;
}
QString sCATport=m_catPort;
#ifdef WIN32
sCATport="\\\\.\\" + m_catPort; //Allow COM ports above 9
#endif
rig->setConf("rig_pathname", sCATport.toLatin1().data());
char buf[80];
sprintf(buf,"%d",m_serialRate);
rig->setConf("serial_speed",buf);
sprintf(buf,"%d",m_dataBits);
rig->setConf("data_bits",buf);
sprintf(buf,"%d",m_stopBits);
rig->setConf("stop_bits",buf);
rig->setConf("serial_handshake",m_handshake.toLatin1().data());
if(m_handshakeIndex != 2) {
rig->setConf("rts_state",m_bRTS ? "ON" : "OFF");
rig->setConf("dtr_state",m_bDTR ? "ON" : "OFF");
}
}
ret=rig->open(m_rig);
if(ret==RIG_OK) {
m_bRigOpen=true;
m_bad=0;
if(m_poll==0) ui->readFreq->setEnabled(true);
m_CATerror=false;
} else {
t="Open rig failed";
msgBox(t);
m_catEnabled=false;
m_bRigOpen=false;
m_CATerror=true;
}
if(m_bRigOpen) {
if(m_poll>0) {
ui->readFreq->setStyleSheet("QPushButton{background-color: #00ff00; \
border-width: 0px; border-radius: 5px;}");
} else {
ui->readFreq->setStyleSheet("QPushButton{background-color: orange; \
border-width: 0px; border-radius: 5px;}");
}
if(m_bSplit) ui->readFreq->setText("S");
if(!m_bSplit) ui->readFreq->setText("");
} else {
if(m_CATerror) ui->readFreq->setStyleSheet("QPushButton{background-color: red; \
border-width: 0px; border-radius: 5px;}");
if(!m_CATerror) ui->readFreq->setStyleSheet("");
ui->readFreq->setText("");
}
}
void MainWindow::on_actionAllow_multiple_instances_triggered(bool checked)
{
m_bMultipleOK=checked;
}
void MainWindow::on_pbR2T_clicked()
{
int n=m_wideGraph->rxFreq();
ui->TxFreqSpinBox->setValue(n);
}
void MainWindow::on_pbT2R_clicked()
{
m_wideGraph->setRxFreq(m_txFreq);
}
void MainWindow::on_readFreq_clicked()
{
if(m_transmitting) return;
m_dontReadFreq=false;
double fMHz=rig->getFreq(RIG_VFO_CURR)/1000000.0;
if(fMHz<0.0) {
QString rt;
rt.sprintf("Rig control error %d\nFailed to read frequency.",
int(1000000.0*fMHz));
msgBox(rt);
m_catEnabled=false;
}
if(fMHz<0.01 or fMHz>1300.0) fMHz=0;
int ndiff=1000000.0*(fMHz-m_dialFreq);
if(ndiff!=0) dialFreqChanged2(fMHz);
}
void MainWindow::on_pbTxMode_clicked()
{
if(m_modeTx=="JT9") {
m_modeTx="JT65";
ui->pbTxMode->setText("Tx JT65 #");
} else {
m_modeTx="JT9";
ui->pbTxMode->setText("Tx JT9 @");
}
m_wideGraph->setModeTx(m_modeTx);
statusChanged();
}
void MainWindow::setXIT(int n)
{
int ret;
m_XIT = 0;
if(m_bRigOpen) {
m_XIT=(n/500)*500 - 1500;
if(m_bXIT) {
ret=rig->setXit((shortfreq_t)m_XIT,RIG_VFO_TX);
if(ret!=RIG_OK) {
QString rt;
rt.sprintf("Setting RIG_VFO_TX failed: %d",ret);
msgBox(rt);
}
}
if(m_bSplit) {
ret=rig->setSplitFreq(MHz(m_dialFreq)+m_XIT,RIG_VFO_B);
}
}
Q_EMIT transmitFrequency (m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0));
}
void MainWindow::setFreq4(int rxFreq, int txFreq)
{
m_rxFreq=rxFreq;
m_txFreq=txFreq;
ui->RxFreqSpinBox->setValue(m_rxFreq);
ui->TxFreqSpinBox->setValue(m_txFreq);
}
void MainWindow::on_cbTxLock_clicked(bool checked)
{
m_lockTxFreq=checked;
m_wideGraph->setLockTxFreq(m_lockTxFreq);
if(m_lockTxFreq) on_pbR2T_clicked();
}
void MainWindow::on_actionTx2QSO_triggered(bool checked)
{
m_tx2QSO=checked;
}
void MainWindow::on_cbPlus2kHz_toggled(bool checked)
{
m_plus2kHz=checked;
on_bandComboBox_activated(m_band);
}
void MainWindow::pollRigFreq()
{
double fMHz;
if(m_dontReadFreq) {
m_dontReadFreq=false;
} else if(!m_transmitting) {
fMHz=rig->getFreq(RIG_VFO_CURR)/1000000.0;
if(fMHz<0.0) {
m_bad++;
if(m_bad>=20) {
QString rt;
rt.sprintf("Rig control error %d\nFailed to read frequency.",
int(1000000.0*fMHz));
msgBox(rt);
m_catEnabled=false;
ui->readFreq->setStyleSheet("QPushButton{background-color: red; \
border-width: 0px; border-radius: 5px;}");
}
} else {
int ndiff=1000000.0*(fMHz-m_dialFreq);
if(ndiff!=0) dialFreqChanged2(fMHz);
}
}
}
void MainWindow::transmit (double snr)
{
if (m_modeTx == "JT65")
{
Q_EMIT sendMessage (NUM_JT65_SYMBOLS, 4096.0 * 12000.0 / 11025.0, m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0), m_audioOutputChannel, true, snr);
}
else
{
Q_EMIT sendMessage (NUM_JT9_SYMBOLS, m_nsps, m_txFreq - (m_bSplit || m_bXIT ? m_XIT : 0), m_audioOutputChannel, true, snr);
}
Q_EMIT startAudioOutputStream (m_audioOutputDevice, AudioDevice::Mono == m_audioOutputChannel ? 1 : 2);
}
void MainWindow::on_outAttenuation_valueChanged (int a)
{
qreal dBAttn (a / 10.); // slider interpreted as hundredths of a dB
ui->outAttenuation->setToolTip (tr ("Transmit digital gain ") + (a ? QString::number (-dBAttn, 'f', 1) : "0") + "dB");
Q_EMIT outAttenuationChanged (dBAttn);
}