From 62c449669f1bca5e2bd655c6b337c2ae7a071ec8 Mon Sep 17 00:00:00 2001 From: Jordan Sherer Date: Tue, 31 Jul 2018 17:48:33 -0400 Subject: [PATCH] Added a prioritized TX queue for beacons (low priority) and automatic replies (normal priority) and eventually outgoing messages (high priority) --- decodedtext.cpp | 14 +++++- mainwindow.cpp | 110 +++++++++++++++++++++++++++++++++++------------ mainwindow.h | 44 +++++++++++++++++-- qpriorityqueue.h | 4 +- 4 files changed, 137 insertions(+), 35 deletions(-) diff --git a/decodedtext.cpp b/decodedtext.cpp index 87a2dbe..cbdec21 100644 --- a/decodedtext.cpp +++ b/decodedtext.cpp @@ -65,12 +65,14 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString DecodedText::DecodedText (QString const& ft8callmessage){ message_ = ft8callmessage; - is_standard_ = false; + is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch(); + tryUnpack(); } bool DecodedText::tryUnpack(){ if(is_standard_){ + message_ = message_.append(" "); return false; } @@ -115,7 +117,15 @@ bool DecodedText::tryUnpackBeacon(){ isBeacon_ = isBeacon; isAlt_ = isAlt; extra_ = parts.at(2); - compound_ = QStringList{ parts.at(0), parts.at(1) }.join("/"); + + QStringList cmp; + if(!parts.at(0).isEmpty()){ + cmp.append(parts.at(0)); + } + if(!parts.at(1).isEmpty()){ + cmp.append(parts.at(1)); + } + compound_ = cmp.join("/"); // BCN|CQ if(isBeacon){ diff --git a/mainwindow.cpp b/mainwindow.cpp index 746e9ed..c268e09 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -4419,14 +4419,20 @@ void MainWindow::guiUpdate() if(m_sec0 % m_TRperiod == 0){ // force rx dirty at least once pre period m_rxDirty = true; + m_rxDisplayDirty = true; } + // once pre second... + // update the dial frequency once per second.. displayDialFrequency(); // process all received activity... processActivity(); + // process outgoing tx queue... + processTxQueue(); + // once processed, lets update the display... displayActivity(); } @@ -5712,6 +5718,14 @@ void MainWindow::addMessageText(QString text, bool clear){ ui->extFreeTextMsgEdit->setFocus(); } +void MainWindow::enqueueMessage(int priority, QString message, int freq, Callback c){ + m_txMessageQueue.enqueue( + PrioritizedMessage{ + QDateTime::currentDateTimeUtc(), priority, message, freq, c + } + ); +} + void MainWindow::resetMessage(){ resetMessageUI(); resetMessageTransmitQueue(); @@ -5743,7 +5757,8 @@ void MainWindow::createMessageTransmitQueue(QString const& text){ QStringList lines; foreach(auto frame, frames){ - lines.append(DecodedText(frame).message()); + auto dt = DecodedText(frame); + lines.append(dt.message()); } logRxTxMessageText(QDateTime::currentDateTimeUtc(), lines.join(""), freq, true); @@ -6101,6 +6116,7 @@ bool MainWindow::prepareNextMessageFrame() bool MainWindow::isFreqOffsetFree(int f, int bw){ foreach(int offset, m_bandActivity.keys()){ + if(qAbs(offset - f) < bw){ return false; } @@ -6143,7 +6159,7 @@ void MainWindow::scheduleBacon(bool first){ // round to 15 second increment int secondsSinceEpoch = (timestamp.toMSecsSinceEpoch()/1000); - int delta = roundUp(secondsSinceEpoch, 15) + 1 + (first ? m_txFirst ? 15 : 30 : qMax(1, m_config.beacon()) * 60) - secondsSinceEpoch; + int delta = roundUp(secondsSinceEpoch, 15) + 1 + (first ? /*m_txFirst ? 15 : 30*/ 0 : qMax(1, m_config.beacon()) * 60) - secondsSinceEpoch; timestamp = timestamp.addSecs(delta); // 25% of the time, switch intervals @@ -6181,27 +6197,6 @@ void MainWindow::prepareBacon(){ return; } - int bw = 50 + 5; - int f = currentFreq(); - if(!isFreqOffsetFree(f, bw)){ - f = findFreeFreqOffset(500, 1500, bw); - } - - // delay beacon if there's not a free frequency or there's something the tx queue or we just recently transmitted - if( - f == 0 || - !m_txFrameQueue.isEmpty() || - !ui->extFreeTextMsgEdit->toPlainText().isEmpty() || - m_lastTxTime.secsTo(QDateTime::currentDateTimeUtc()) < 30 - ){ - if(ui->beaconButton->isChecked()){ - scheduleBacon(false); - } - return; - } - - setFreqForRestore(f, true); - QStringList lines; QString call = m_config.my_callsign(); @@ -6218,6 +6213,10 @@ void MainWindow::prepareBacon(){ // FT8Call Style lines.append(QString("%1: BCN %2").arg(call).arg(grid)); + // Queue the beacon + enqueueMessage(PriorityLow, lines.join(QChar('\n')), currentFreq(), nullptr); + + #if 0 if(!m_callActivity.isEmpty()){ auto callsHeard = QSet::fromList(m_callActivity.keys()); @@ -6238,11 +6237,14 @@ void MainWindow::prepareBacon(){ } #endif + +#if 0 addMessageText(lines.join(QChar('\n'))); ui->startTxButton->setChecked(true); scheduleBacon(false); +#endif } @@ -6284,10 +6286,6 @@ void MainWindow::toggleTx(bool start){ ui->startTxButton->setChecked(start); } -void MainWindow::splitAndSendNextMessage() -{ -} - void MainWindow::on_rbNextFreeTextMsg_toggled (bool status) { if (status) { @@ -9019,6 +9017,10 @@ void MainWindow::processCommandActivity() { continue; } + + enqueueMessage(PriorityNormal, reply, d.freq, nullptr); + + #if 0 addMessageText(reply); @@ -9055,8 +9057,58 @@ void MainWindow::processSpots() { // Process spots to be sent... } +void MainWindow::processTxQueue(){ + if(m_txMessageQueue.isEmpty()){ + return; + } + + // grab the next message... + auto head = m_txMessageQueue.head(); + + // decide if it's ok to transmit... + int f = head.freq; + if(!isFreqOffsetFree(f, 60)){ + f = findFreeFreqOffset(500, 2500, 60); + } + + // we need a valid frequency... + if(f == 0){ + return; + } + + // tx frame queue needs to be empty... + if(!m_txFrameQueue.isEmpty()){ + return; + } + + // our message box needs to be empty... + if(!ui->extFreeTextMsgEdit->toPlainText().isEmpty()){ + return; + } + +#if 0 + // and we need to have not transmitted in the 30 seconds... + if(m_lastTxTime.secsTo(QDateTime::currentDateTimeUtc()) < 30){ + return; + } +#endif + + // dequeue the next message from the queue... + auto message = m_txMessageQueue.dequeue(); + + // add the message to the outgoing message text box + addMessageText(message.message, true); + + // then transmit... + toggleTx(true); + + if(message.callback){ + message.callback(); + } +} + void MainWindow::displayActivity(bool force) { - if (!m_rxDirty && !force) { + if (!m_rxDisplayDirty && !force) { return; } @@ -9065,6 +9117,8 @@ void MainWindow::displayActivity(bool force) { // Call Activity displayCallActivity(); + + m_rxDisplayDirty = false; } void MainWindow::displayBandActivity() { diff --git a/mainwindow.h b/mainwindow.h index 5a5aa2c..1069f0a 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -23,6 +23,8 @@ #include #include +#include + #include "AudioDevice.hpp" #include "commons.h" #include "Radio.hpp" @@ -39,6 +41,7 @@ #include "MessageBox.hpp" #include "NetworkAccessManager.hpp" #include "qorderedmap.h" +#include "qpriorityqueue.h" #include "varicode.h" #define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync @@ -86,6 +89,9 @@ class MultiSettings; class EqualizationToolsDialog; class DecodedText; +using namespace std; +typedef std::function Callback; + class MainWindow : public QMainWindow { Q_OBJECT; @@ -127,6 +133,7 @@ public slots: void clearActivity(); int logRxTxMessageText(QDateTime date, QString text, int freq, bool tx, int block=-1); void addMessageText(QString text, bool clear=false); + void enqueueMessage(int priority, QString message, int freq, Callback c); void resetMessage(); void resetMessageUI(); void restoreMessage(); @@ -203,7 +210,6 @@ private slots: void on_txb6_clicked(); void on_startTxButton_toggled(bool checked); void toggleTx(bool start); - void splitAndSendNextMessage(); void on_rbNextFreeTextMsg_toggled (bool status); void on_lookupButton_clicked(); void on_addButton_clicked(); @@ -642,6 +648,14 @@ private: QSet m_pfx; QSet m_sfx; + struct FoxQSO + { + QString grid; + QString sent; + QString rcvd; + qint32 ncall; + }; + struct CallDetail { QString call; @@ -684,11 +698,35 @@ private: }; bool m_rxDirty; + bool m_rxDisplayDirty; int m_txFrameCount; QString m_lastTxMessage; QDateTime m_lastTxTime; - QQueue m_txFrameQueue; + + enum Priority { + PriorityLow = 0, + PriorityNormal = 10, + PriorityHigh = 100 + }; + + struct PrioritizedMessage { + QDateTime date; + int priority; + QString message; + int freq; + Callback callback; + + friend bool operator <(PrioritizedMessage const &a, PrioritizedMessage const &b){ + if(a.priority < b.priority){ + return true; + } + return a.date < b.date; + } + }; + + QPriorityQueue m_txMessageQueue; // messages to be sent + QQueue m_txFrameQueue; // frames to be sent QQueue m_rxFrameQueue; QQueue m_rxCommandQueue; QMap m_compoundCallCache; // base callsign -> compound callsign @@ -722,7 +760,6 @@ private: QQueue m_foxQSOinProgress; //QSOs in progress: Fox has sent a report QQueue m_foxRateQueue; - bool m_nextBeaconPaused = false; QDateTime m_nextBeacon; QDateTime m_dateTimeQSOOn; @@ -801,6 +838,7 @@ private: void processBufferedActivity(); void processCommandActivity(); void processSpots(); + void processTxQueue(); void displayActivity(bool force=false); void displayBandActivity(); void displayCallActivity(); diff --git a/qpriorityqueue.h b/qpriorityqueue.h index 595568a..7f8268e 100644 --- a/qpriorityqueue.h +++ b/qpriorityqueue.h @@ -117,8 +117,8 @@ public: // like qqueue inline void enqueue(const T &t) { push(t); } inline T dequeue() { T t = d.top(); d.pop(); return t; } - inline T &head() { top(); } - inline const T &head() const { top(); } + inline T &head() { return const_cast(top()); } + inline const T &head() const { return top(); } // stl compatibility typedef int size_type;