From 9e9c996813238fdcddcfbd8642fec3695e66e2b9 Mon Sep 17 00:00:00 2001 From: Jordan Sherer Date: Wed, 25 Jul 2018 22:49:19 -0400 Subject: [PATCH] Refactor message buffering for relay --- mainwindow.cpp | 118 +++++++++++++++++++++++++++---------------------- mainwindow.h | 8 +++- varicode.cpp | 15 +++++-- varicode.h | 3 +- 4 files changed, 85 insertions(+), 59 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 8aca4dc..f5a19b9 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -62,7 +62,6 @@ #include "ui_mainwindow.h" #include "moc_mainwindow.cpp" -#define TEST_ALL_OR_NOTHING 1 // 0 extern "C" { //----------------------------------------------------- C and Fortran routines @@ -3247,39 +3246,9 @@ void MainWindow::readFromStdout() //readFromStdout d.snr = decodedtext.snr(); m_bandActivity[offset].append(d); -#if TEST_ALL_OR_NOTHING - if(m_messageCache.contains(d.freq/10*10)){ - m_messageCache[d.freq/10*10].second.append(d); - - if(d.bits == Varicode::FT8CallLast){ - auto c = m_messageCache[d.freq/10*10].first; - auto fs = m_messageCache[d.freq/10*10].second; - if(!fs.isEmpty()){ - qDebug() << "MESSAGE COMPLETE:" << c.from << c.to; - QString message; - foreach(auto f, fs){ - message.append(f.text); - } - QString checksum = message.left(3); - message = message.mid(3); - bool valid = Varicode::checksum16Valid(checksum, message); - qDebug() << "> CHECKSUM:" << checksum; - qDebug() << "> MESSAGE:" << message; - qDebug() << "> VALID:" << valid; - - // TODO: jsherer - we should process this where all the other commands are processes... - if(valid){ - addMessageText(QString("%1 ACK\n").arg(c.from), true); - addMessageText(message, false); - if(ui->autoReplyButton->isChecked()){ - toggleTx(true); - } - } - } - m_messageCache.remove(d.freq/10*10); - } + if(m_messageBuffer.contains(d.freq/10*10)){ + m_messageBuffer[d.freq/10*10].msgs.append(d); } -#endif while(m_bandActivity[offset].count() > 10){ m_bandActivity[offset].removeFirst(); @@ -3354,16 +3323,13 @@ void MainWindow::readFromStdout() //readFromStdout d.freq = decodedtext.frequencyOffset(); d.snr = decodedtext.snr(); d.utcTimestamp = QDateTime::currentDateTimeUtc(); - m_rxCommandQueue.append(d); -#if TEST_ALL_OR_NOTHING - // TODO: jsherer - process this elsewhere? - if(d.cmd == "|"){ - // cache the message buffer commands - m_messageCache[d.freq/10*10].first = d; - m_messageCache[d.freq/10*10].second.clear(); + if(Varicode::isCommandBuffered(d.cmd)){ + m_messageBuffer[d.freq/10*10].cmd = d; + m_messageBuffer[d.freq/10*10].msgs.clear(); + } else { + m_rxCommandQueue.append(d); } -#endif CallDetail cd; cd.call = d.from; @@ -3416,7 +3382,7 @@ void MainWindow::readFromStdout() //readFromStdout } } - //Right (Rx Frequency) window + //Right (Rx Frequency) window bool bDisplayRight=bAvgMsg; int audioFreq=decodedtext.frequencyOffset(); @@ -5667,7 +5633,8 @@ QPair MainWindow::buildFT8MessageFrames(QString const& QString stdFrame = parseFT8Message(line, &isFree); int n = 0; - QString dirFrame = Varicode::packDirectedMessage(line, basecall, &n); + QString dirCmd; + QString dirFrame = Varicode::packDirectedMessage(line, basecall, &dirCmd, &n); int m = 0; QString datFrame = Varicode::packDataMessage(line.left(21) + "\x04", &m); // 63 / 3 = 21 (maximum number of 3bit chars we could possibly stuff in here) @@ -5724,15 +5691,10 @@ QPair MainWindow::buildFT8MessageFrames(QString const& lines.append(line.left(n) + " "); line = line.mid(n); -#if TEST_ALL_OR_NOTHING - // TODO: jsherer - don't do this... refactor pack to return the packed frame _and_ its components instead - if(Varicode::unpackDirectedMessage(dirFrame).at(2) == "|"){ - // TODO: jsherer - this is how we can add 16-bit checksum to the message, just encode it in the data... - if(!line.isEmpty()){ - line = Varicode::checksum16(line) + line; + if(Varicode::isCommandBuffered(dirCmd) && !line.isEmpty()){ + // TODO: jsherer - this is how we can add 16-bit checksum to the message, just encode it in the data... + line = Varicode::checksum16(line) + " " + line; } - } -#endif } if(useDat){ @@ -7254,7 +7216,17 @@ void MainWindow::buildQueryMenu(QMenu * menu){ toggleTx(true); }); - //menu->addAction("| - Please relay the following message")->setEnabled(false); + auto retransmitAction = menu->addAction("|message - Please ACK and retransmit the following message"); + retransmitAction->setDisabled(isAllCall); + connect(retransmitAction, &QAction::triggered, this, [this](){ + + QString selectedCall = callsignSelected(); + if(selectedCall.isEmpty()){ + return; + } + + addMessageText(QString("%1|").arg(selectedCall), true); + }); menu->addSeparator(); @@ -8634,9 +8606,36 @@ void MainWindow::displayActivity(bool force){ } } + // Buffered Activity + foreach(auto freq, m_messageBuffer.keys()){ + auto buffer = m_messageBuffer[freq]; + + if(buffer.msgs.isEmpty()){ + continue; + } + + if(buffer.msgs.last().bits == Varicode::FT8Call){ + continue; + } + + QString message; + foreach(auto part, buffer.msgs){ + message.append(part.text); + } + + QString checksum = message.left(3); + message = message.mid(4); + + if(Varicode::checksum16Valid(checksum, message)){ + buffer.cmd.text = message; + m_rxCommandQueue.append(buffer.cmd); + } + + // regardless of valid or not, remove the "complete" buffered message from the buffer cache + m_messageBuffer.remove(freq); + } // Command Activity - if(m_txFrameQueue.isEmpty() && !m_rxCommandQueue.isEmpty()){ int f = currentFreq(); @@ -8703,7 +8702,8 @@ void MainWindow::displayActivity(bool force){ } // QUERIED STATIONS HEARD else if(d.cmd == "$" && !isAllCall){ - + int i = 0; + int maxStations = 4; auto calls = m_callActivity.keys(); qSort(calls.begin(), calls.end(), [this](QString const &a, QString const &b){ auto left = m_callActivity[a]; @@ -8713,14 +8713,24 @@ void MainWindow::displayActivity(bool force){ QStringList lines; foreach(auto call, calls){ + if(i >= maxStations){ + break; + } if(Radio::base_callsign(call) == Radio::base_callsign(m_config.my_callsign())){ continue; } + auto d = m_callActivity[call]; lines.append(QString("%1 SNR %2").arg(Radio::base_callsign(call)).arg(Varicode::formatSNR(d.snr))); + i++; } reply = lines.join('\n'); } + // PROCESS RETRANSMIT + else if(d.cmd == "|" && !isAllCall){ + // TODO: jsherer - perhaps parse d.text and ensure it is a valid message? + reply = QString("%1 ACK\n%2").arg(d.from).arg(d.text); + } if(reply.isEmpty()){ continue; diff --git a/mainwindow.h b/mainwindow.h index f5282e4..8e6c2a7 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -656,6 +656,7 @@ private: int freq; QDateTime utcTimestamp; int snr; + QString text; }; struct ActivityDetail @@ -670,6 +671,11 @@ private: int snr; }; + struct MessageBuffer { + CommandDetail cmd; + QList msgs; + }; + bool m_rxDirty; int m_txFrameCount; QString m_lastTxMessage; @@ -686,7 +692,7 @@ private: QCache m_rxCallCache; // call -> last freq seen QMap m_rxFrameBlockNumbers; // freq -> block QMap> m_bandActivity; // freq -> [(text, last timestamp), ...] - QMap>> m_messageCache; // freq -> (cmd, [frames, ...]) + QMap m_messageBuffer; // freq -> (cmd, [frames, ...]) QMap m_callActivity; // call -> (last freq, last timestamp) QSet m_callSeenBeacon; // call int m_previousFreq; diff --git a/varicode.cpp b/varicode.cpp index c8f4a7a..21315fb 100644 --- a/varicode.cpp +++ b/varicode.cpp @@ -65,6 +65,8 @@ QMap directed_cmds = { QSet allowed_cmds = {0, 1, 2, 3, 4, 5, 6, /*7,*/ 23, 24, 25, 26, 27, 28, 29, 30, 31}; +QSet buffered_cmds = {6, 7}; + QRegularExpression directed_re("^" "(?[A-Z0-9/]+)" "(?\\s?(?:AGN[?]|RR|73|YES|NO|SNR|PWR|ACK|[?@&$^%|! ]))" @@ -679,6 +681,10 @@ bool Varicode::isCommandAllowed(const QString &cmd){ return directed_cmds.contains(cmd) && allowed_cmds.contains(directed_cmds[cmd]); } +bool Varicode::isCommandBuffered(const QString &cmd){ + return directed_cmds.contains(cmd) && buffered_cmds.contains(directed_cmds[cmd]); +} + QString Varicode::packCompoundMessage(const QString &baseCallsign, const QString &fix, bool isPrefix, quint16 num){ QString frame; @@ -751,7 +757,7 @@ QStringList Varicode::unpackCompoundMessage(const QString &text){ return unpacked; } -QString Varicode::packDirectedMessage(const QString &text, const QString &baseCallsign, int *n){ +QString Varicode::packDirectedMessage(const QString &text, const QString &baseCallsign, QString * pCmd, int *n){ QString frame; auto match = directed_re.match(text); @@ -824,6 +830,7 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &baseCa Varicode::intToBits(packed_cmd % 32, 5) ); + if(pCmd) *pCmd = cmd; if(n) *n = match.captured(0).length(); return Varicode::pack64bits(Varicode::bitsToInt(bits)) + Varicode::pack5bits(packed_extra % 32); } @@ -853,10 +860,12 @@ QStringList Varicode::unpackDirectedMessage(const QString &text){ quint8 packed_cmd = Varicode::bitsToInt(Varicode::strToBits(bits.mid(59, 5))); QString from = Varicode::unpackCallsign(packed_from).trimmed(); + QString to = Varicode::unpackCallsign(packed_to).trimmed(); + QString cmd = directed_cmds.key(packed_cmd % 32); unpacked.append(from); - unpacked.append(Varicode::unpackCallsign(packed_to).trimmed()); - unpacked.append(directed_cmds.key(packed_cmd % 32)); + unpacked.append(to); + unpacked.append(cmd); int num = (num_flag ? -1 : 1) * extra; if(num != -31){ diff --git a/varicode.h b/varicode.h index 7bc7e91..75b4925 100644 --- a/varicode.h +++ b/varicode.h @@ -76,11 +76,12 @@ public: static QString unpackGrid(quint16 value); static bool isCommandAllowed(const QString &cmd); + static bool isCommandBuffered(const QString &cmd); static QString packCompoundMessage(const QString &baseCallsign, const QString &fix, bool isPrefix, quint16 num); static QStringList unpackCompoundMessage(const QString &text); - static QString packDirectedMessage(QString const& text, QString const& callsign, int *n); + static QString packDirectedMessage(QString const& text, QString const& callsign, QString * pCmd, int *n); static QStringList unpackDirectedMessage(QString const& text); static QString packDataMessage(QString const& text, int *n);