From 72bf58ad4c0b21a788d3f6f2b705c2aa0cef3e54 Mon Sep 17 00:00:00 2001 From: Jordan Sherer Date: Wed, 5 Jun 2019 11:33:21 -0400 Subject: [PATCH] Added n3fjp mapping of custom fields --- TCPClient.cpp | 7 ++-- TCPClient.h | 2 +- js8call.pro | 3 +- logbook/adif.cpp | 4 +-- logbook/adif.h | 3 +- logbook/logbook.h | 1 + logbook/n3fjp.h | 82 +++++++++++++++++++++++++++++++++++++++++++++++ logqso.cpp | 71 ++++++++++++++++++++++------------------ logqso.h | 3 +- mainwindow.cpp | 55 ++++++++++++++++++++++++++----- mainwindow.h | 2 +- 11 files changed, 182 insertions(+), 51 deletions(-) create mode 100644 logbook/n3fjp.h diff --git a/TCPClient.cpp b/TCPClient.cpp index 31b629b..5062cd6 100644 --- a/TCPClient.cpp +++ b/TCPClient.cpp @@ -58,24 +58,21 @@ TCPClient::TCPClient(QObject *parent) : QObject(parent) bool TCPClient::ensureConnected(QString host, port_type port, int msecs){ if(!m_->isConnected(host, port)){ - //qDebug() << "connecting to" << host << port; m_->connectToHost(host, port); } return m_->waitForConnected(msecs); } -bool TCPClient::sendNetworkMessage(QString host, port_type port, QByteArray const &message, bool crlf){ - if(!ensureConnected(host, port)){ +bool TCPClient::sendNetworkMessage(QString host, port_type port, QByteArray const &message, bool crlf, int msecs){ + if(!ensureConnected(host, port, msecs)){ return false; } - //qDebug() << "connecting to" << host << port; qint64 n = m_->send(message, crlf); if(n <= 0){ return false; } - //qDebug() << "sent" << n << "bytes" << message; return m_->flush(); } diff --git a/TCPClient.h b/TCPClient.h index 9ee23d3..59e1261 100644 --- a/TCPClient.h +++ b/TCPClient.h @@ -18,7 +18,7 @@ signals: public slots: Q_SLOT bool ensureConnected(QString host, port_type port, int msecs = 5000); - Q_SLOT bool sendNetworkMessage(QString host, port_type port, QByteArray const &message, bool crlf=true); + Q_SLOT bool sendNetworkMessage(QString host, port_type port, QByteArray const &message, bool crlf=true, int msecs=5000); private: class impl; diff --git a/js8call.pro b/js8call.pro index dbcb2fd..d978ff4 100644 --- a/js8call.pro +++ b/js8call.pro @@ -117,7 +117,8 @@ HEADERS += qt_helpers.hpp \ Inbox.h \ messagewindow.h \ SpotClient.h \ - TCPClient.h + TCPClient.h \ + logbook/n3fjp.h INCLUDEPATH += qmake_only diff --git a/logbook/adif.cpp b/logbook/adif.cpp index 0258bd1..a1f092a 100644 --- a/logbook/adif.cpp +++ b/logbook/adif.cpp @@ -333,7 +333,7 @@ QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QStri , QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn , QDateTime const& dateTimeOff, QString const& band, QString const& comments , QString const& name, QString const& strDialFreq, QString const& m_myCall - , QString const& m_myGrid, QString const& operator_call, QMap const &additionalFields) + , QString const& m_myGrid, QString const& operator_call, QMap const &additionalFields) { QString t; t = "" + hisCall; @@ -365,7 +365,7 @@ QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QStri ">" + operator_call; foreach(auto key, additionalFields.keys()){ - auto value = additionalFields[key]; + auto value = additionalFields[key].toString(); t += QString(" <%1:%2>%3").arg(key).arg(value.length()).arg(value); } diff --git a/logbook/adif.h b/logbook/adif.h index 1698cd2..64a5a3a 100644 --- a/logbook/adif.h +++ b/logbook/adif.h @@ -13,6 +13,7 @@ #include #include #include +#include #else #include #endif @@ -42,7 +43,7 @@ class ADIF , QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff , QString const& band, QString const& comments, QString const& name , QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid - , QString const& operator_call, const QMap &additionalFields); + , QString const& operator_call, const QMap &additionalFields); struct QSO diff --git a/logbook/logbook.h b/logbook/logbook.h index cc9000a..02ba14c 100644 --- a/logbook/logbook.h +++ b/logbook/logbook.h @@ -13,6 +13,7 @@ #include "countrydat.h" #include "countriesworked.h" #include "adif.h" +#include "n3fjp.h" class QDir; diff --git a/logbook/n3fjp.h b/logbook/n3fjp.h new file mode 100644 index 0000000..c22a4c2 --- /dev/null +++ b/logbook/n3fjp.h @@ -0,0 +1,82 @@ +#ifndef N3FJP_H +#define N3FJP_H + + +// Mapping between ADIF field to N3FJP field +static const QMap N3FJP_ADIF_MAP = { + {"AGE", "fldAge"}, + //{"", "fldARCI"}, + {"BAND", "fldBand"}, + {"CALL", "fldCall"}, + //{"", "fldCategory"}, + {"CHECK", "fldCheck"}, + {"CLASS", "fldClass"}, + {"COMMENT", "fldComments"}, + {"COMMENT_INTL", "fldComments"}, + //{"", "fldComputerName"}, + {"CONTEST_ID", "fldContestID"}, + {"CONT", "fldContinent"}, + {"DXCC", "fldCountryDXCC"}, + //{"", "fldCountryWorked"}, + {"COUNTRY", "fldCountyR"}, + {"COUNTRY_INTL", "fldCountyR"}, + {"MY_COUNTRY", "fldCountyS"}, + {"MY_COUNTRY_INTL", "fldCountyS"}, + {"CQZ", "fldCQZone"}, + {"QSO_DATE", "fldDateStr"}, + {"FISTS", "fldFists"}, + {"FISTS_CC", "fldFists"}, + {"FREQ", "fldFrequency"}, + //{"", "fldFuture1"}, + //{"", "fldFuture2"}, + {"GRIDSQUARE", "fldGridR"}, + {"MY_GRIDSQUARE", "fldGridS"}, + //{"", "fldIARUZone"}, + //{"", "fldInitials"}, + {"IOTA", "fldIOTA"}, + {"ITUZ", "fldITUZone"}, + //{"", "fldLightHouse"}, + {"MODE", "fldMode"}, + {"CONTEST_ID", "fldModeContest"}, + {"NAME", "fldNameR"}, + {"NAME_INTL", "fldNameR"}, + {"MY_NAME", "fldNameS"}, + {"MY_NAME_INTL", "fldNameS"}, + {"OPERATOR", "fldOperator"}, + {"*1", "fldOther1"}, + {"*2", "fldOther2"}, + {"*3", "fldOther3"}, + {"*4", "fldOther4"}, + {"*5", "fldOther5"}, + {"*6", "fldOther6"}, + {"*7", "fldOther7"}, + {"*8", "fldOther8"}, + //{"", "fldPoints"}, + {"RX_PWR", "fldPower"}, + {"TX_PWR", "fldPower"}, + {"PRECEDENCE", "fldPrecedence"}, + {"PFX", "fldPrefix"}, + {"PROP_MODE", "fldPropMode"}, + {"QSL_RCVD_VIA", "fldQSLConfByR"}, + {"QSL_SENT_VIA", "fldQSLConfByS"}, + {"QSL_RCVD", "fldQSLR"}, + {"QSL_SENT", "fldQSLS"}, + {"QTH", "fldQTHGroup"}, + {"QTH_INTL", "fldQTHGroup"}, + {"RST_RCVD", "fldRstR"}, + {"RST_SENT", "fldRstS"}, + {"SAT_NAME", "fldSatName"}, + {"ARRL_SECT", "fldSection"}, + {"SRX", "fldSerialNoR"}, + {"STX", "fldSerialNoS"}, + {"SRX_STRING", "fldSPC"}, + {"SRX", "fldSPCNum"}, + {"STATE", "fldState"}, + {"STATION_CALLSIGN", "fldStation"}, + {"TEN_TEN", "fldTenTen"}, + {"TIME_OFF", "fldTimeOffStr"}, + {"TIME_ON", "fldTimeOnStr"}, + //{"", "fldTransmitterID"}, +}; + +#endif // N3FJP_H diff --git a/logqso.cpp b/logqso.cpp index 4d13edf..c2715fd 100644 --- a/logqso.cpp +++ b/logqso.cpp @@ -92,6 +92,18 @@ void LogQSO::createAdditionalField(QString key, QString value){ m_additionalFieldsControls.append(l); } +QMap LogQSO::collectAdditionalFields(){ + QMap additionalFields; + foreach(auto field, m_additionalFieldsControls){ + auto key = field->property("fieldKey").toString(); + if(key.isEmpty()){ + continue; + } + additionalFields[key] = QVariant(field->text()); + } + return additionalFields; +} + void LogQSO::resetAdditionalFields(){ if(m_additionalFieldsControls.isEmpty()){ return; @@ -207,15 +219,6 @@ void LogQSO::accept() QString hisCall,hisGrid,mode,submode,rptSent,rptRcvd,dateOn,dateOff,timeOn,timeOff,band,operator_call; QString comments,name; - QMap additionalFields; - foreach(auto field, m_additionalFieldsControls){ - auto key = field->property("fieldKey").toString(); - if(key.isEmpty()){ - continue; - } - additionalFields[key] = field->text(); - } - hisCall=ui->call->text().toUpper(); hisGrid=ui->grid->text().toUpper(); mode = ui->mode->text().toUpper(); @@ -239,6 +242,8 @@ void LogQSO::accept() auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (filename); adifile.init(adifilePath); + auto additionalFields = collectAdditionalFields(); + QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, submode, rptSent, rptRcvd, m_dateTimeOn, m_dateTimeOff, band , comments, name, strDialFreq, m_myCall, m_myGrid, operator_call, additionalFields)}; @@ -248,38 +253,42 @@ void LogQSO::accept() tr ("Cannot open \"%1\"").arg (adifilePath)); } - // Log to N1MM Logger - if (m_config->broadcast_to_n1mm() && m_config->valid_n1mm_info()) { - const QHostAddress n1mmhost = QHostAddress(m_config->n1mm_server_name()); - QUdpSocket _sock; - auto rzult = _sock.writeDatagram (ADIF + " ", n1mmhost, quint16(m_config->n1mm_server_port())); - if (rzult == -1) { - MessageBox::warning_message (this, tr ("Error sending log to N1MM"), - tr ("Write returned \"%1\"").arg (rzult)); - } - } - -//Log this QSO to file "js8call.log" + //Log this QSO to file "js8call.log" static QFile f {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("js8call.log")}; if(!f.open(QIODevice::Text | QIODevice::Append)) { MessageBox::warning_message (this, tr ("Log file error"), tr ("Cannot open \"%1\" for append").arg (f.fileName ()), tr ("Error: %1").arg (f.errorString ())); } else { - QString logEntry=m_dateTimeOn.date().toString("yyyy-MM-dd,") + - m_dateTimeOn.time().toString("hh:mm:ss,") + - m_dateTimeOff.date().toString("yyyy-MM-dd,") + - m_dateTimeOff.time().toString("hh:mm:ss,") + hisCall + "," + - hisGrid + "," + strDialFreq + "," + (mode == "MFSK" ? "JS8" : mode) + - "," + rptSent + "," + rptRcvd + - "," + comments + "," + name; + QStringList logEntryItems = { + m_dateTimeOn.date().toString("yyyy-MM-dd"), + m_dateTimeOn.time().toString("hh:mm:ss"), + m_dateTimeOff.date().toString("yyyy-MM-dd"), + m_dateTimeOff.time().toString("hh:mm:ss"), + hisCall, + hisGrid, + strDialFreq, + (mode == "MFSK" ? "JS8" : mode), + rptSent, + rptRcvd, + comments, + name + }; + + if(!additionalFields.isEmpty()){ + foreach(auto value, additionalFields.values()){ + logEntryItems.append(value.toString()); + } + } + QTextStream out(&f); - out << logEntry << endl; + out << logEntryItems.join(",") << endl; f.close(); } -//Clean up and finish logging - Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, submode, rptSent, rptRcvd, comments, name,m_dateTimeOn, operator_call, m_myCall, m_myGrid, ADIF); + //Clean up and finish logging + Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, submode, rptSent, rptRcvd, comments, name,m_dateTimeOn, operator_call, m_myCall, m_myGrid, ADIF, additionalFields); + QDialog::accept(); } diff --git a/logqso.h b/logqso.h index 3b6e9bc..dd3c762 100644 --- a/logqso.h +++ b/logqso.h @@ -45,7 +45,7 @@ signals: , QString const& rpt_sent, QString const& rpt_received , QString const& comments , QString const& name, QDateTime const& QSO_date_on, QString const& operator_call - , QString const& my_call, QString const& my_grid, QByteArray const& ADIF); + , QString const& my_call, QString const& my_grid, QByteArray const& ADIF, QMap const &additionalFields); protected: void hideEvent (QHideEvent *); @@ -53,6 +53,7 @@ protected: private slots: void createAdditionalField(QString key={}, QString value={}); void resetAdditionalFields(); + QMap collectAdditionalFields(); void on_add_new_field_button_pressed(); void on_start_now_button_pressed(); void on_end_now_button_pressed(); diff --git a/mainwindow.cpp b/mainwindow.cpp index 8e8c379..46098ef 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "APRSISClient.h" #include "revision_utils.hpp" @@ -6624,6 +6626,7 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button } QString comments = ui->textEditRX->textCursor().selectedText(); + m_logDlg->initLogQSO (call.trimmed(), grid.trimmed(), m_modeTx == "FT8" ? "JS8" : m_modeTx, m_rptSent, m_rptRcvd, m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + ui->TxFreqSpinBox->value(), m_config.my_callsign(), m_config.my_grid(), @@ -6636,11 +6639,12 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, , QString const& rpt_sent, QString const& rpt_received , QString const& comments , QString const& name, QDateTime const& QSO_date_on, QString const& operator_call - , QString const& my_call, QString const& my_grid, QByteArray const& ADIF) + , QString const& my_call, QString const& my_grid, QByteArray const& ADIF, QMap const &additionalFields) { QString date = QSO_date_on.toString("yyyyMMdd"); m_logBook.addAsWorked (m_hisCall, m_config.bands ()->find (m_freqNominal), mode, submode, date, name, comments); + // Log to JS8Call API if(m_config.udpEnabled()){ sendNetworkMessage("LOG.QSO", QString(ADIF), { {"UTC.ON", QVariant(QSO_date_on.toMSecsSinceEpoch())}, @@ -6656,10 +6660,23 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, {"COMMENTS", QVariant(comments)}, {"STATION.OP", QVariant(operator_call)}, {"STATION.CALL", QVariant(my_call)}, - {"STATION.GRID", QVariant(my_grid)} + {"STATION.GRID", QVariant(my_grid)}, + {"EXTRA", additionalFields} }); } + // Log to N1MM Logger + if (m_config.broadcast_to_n1mm() && m_config.valid_n1mm_info()) { + const QHostAddress n1mmhost = QHostAddress(m_config.n1mm_server_name()); + QUdpSocket _sock; + auto rzult = _sock.writeDatagram (ADIF + " ", n1mmhost, quint16(m_config.n1mm_server_port())); + if (rzult == -1) { + MessageBox::warning_message (this, tr ("Error sending log to N1MM"), + tr ("Write returned \"%1\"").arg (rzult)); + } + } + + // Log to N3FJP Logger if(m_config.broadcast_to_n3fjp() && m_config.valid_n3fjp_info()){ QString data = QString( "" @@ -6678,6 +6695,7 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, "%9" "%10" "%11" + "%12" ""); data = data.arg(QSO_date_on.toString("yyyy/MM/dd")); @@ -6692,15 +6710,36 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, data = data.arg(rpt_sent); data = data.arg(rpt_received); + int other = 0; + QStringList additional; + if(!additionalFields.isEmpty()){ + foreach(auto key, additionalFields.keys()){ + QString n3key; + if(N3FJP_ADIF_MAP.contains(key)){ + n3key = N3FJP_ADIF_MAP.value(key); + } else { + other++; + n3key = N3FJP_ADIF_MAP.value(QString("*%1").arg(other)); + } + + if(n3key.isEmpty()){ + break; + } + auto value = additionalFields[key].toString(); + additional.append(QString("<%1>%2").arg(n3key).arg(value)); + } + } + data = data.arg(additional.join("")); + auto host = m_config.n3fjp_server_name(); auto port = m_config.n3fjp_server_port(); - m_n3fjpClient->sendNetworkMessage(host, port, data.toLocal8Bit()); - - QTimer::singleShot(300, this, [this, host, port](){ - m_n3fjpClient->sendNetworkMessage(host, port, ""); - m_n3fjpClient->sendNetworkMessage(host, port, "\r\n"); - }); + if(m_n3fjpClient->sendNetworkMessage(host, port, data.toLocal8Bit(), 100)){ + QTimer::singleShot(300, this, [this, host, port](){ + m_n3fjpClient->sendNetworkMessage(host, port, "", 100); + m_n3fjpClient->sendNetworkMessage(host, port, "\r\n", 100); + }); + } } // reload the logbook data diff --git a/mainwindow.h b/mainwindow.h index f06136c..8c3c7dd 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -352,7 +352,7 @@ private slots: , QString const& rpt_sent, QString const& rpt_received , QString const& comments , QString const& name, QDateTime const& QSO_date_on, QString const& operator_call - , QString const& my_call, QString const& my_grid, QByteArray const& ADIF); + , QString const& my_call, QString const& my_grid, QByteArray const& ADIF, const QMap &additionalFields); void on_bandComboBox_currentIndexChanged (int index); void on_bandComboBox_activated (int index); void on_readFreq_clicked();