Added a prioritized TX queue for beacons (low priority) and automatic replies (normal priority) and eventually outgoing messages (high priority)

This commit is contained in:
Jordan Sherer 2018-07-31 17:48:33 -04:00
parent f0de2f2ba1
commit 62c449669f
4 changed files with 137 additions and 35 deletions

View File

@ -65,12 +65,14 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
DecodedText::DecodedText (QString const& ft8callmessage){ DecodedText::DecodedText (QString const& ft8callmessage){
message_ = ft8callmessage; message_ = ft8callmessage;
is_standard_ = false; is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
tryUnpack(); tryUnpack();
} }
bool DecodedText::tryUnpack(){ bool DecodedText::tryUnpack(){
if(is_standard_){ if(is_standard_){
message_ = message_.append(" ");
return false; return false;
} }
@ -115,7 +117,15 @@ bool DecodedText::tryUnpackBeacon(){
isBeacon_ = isBeacon; isBeacon_ = isBeacon;
isAlt_ = isAlt; isAlt_ = isAlt;
extra_ = parts.at(2); 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 // BCN|CQ
if(isBeacon){ if(isBeacon){

View File

@ -4419,14 +4419,20 @@ void MainWindow::guiUpdate()
if(m_sec0 % m_TRperiod == 0){ if(m_sec0 % m_TRperiod == 0){
// force rx dirty at least once pre period // force rx dirty at least once pre period
m_rxDirty = true; m_rxDirty = true;
m_rxDisplayDirty = true;
} }
// once pre second...
// update the dial frequency once per second.. // update the dial frequency once per second..
displayDialFrequency(); displayDialFrequency();
// process all received activity... // process all received activity...
processActivity(); processActivity();
// process outgoing tx queue...
processTxQueue();
// once processed, lets update the display... // once processed, lets update the display...
displayActivity(); displayActivity();
} }
@ -5712,6 +5718,14 @@ void MainWindow::addMessageText(QString text, bool clear){
ui->extFreeTextMsgEdit->setFocus(); 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(){ void MainWindow::resetMessage(){
resetMessageUI(); resetMessageUI();
resetMessageTransmitQueue(); resetMessageTransmitQueue();
@ -5743,7 +5757,8 @@ void MainWindow::createMessageTransmitQueue(QString const& text){
QStringList lines; QStringList lines;
foreach(auto frame, frames){ foreach(auto frame, frames){
lines.append(DecodedText(frame).message()); auto dt = DecodedText(frame);
lines.append(dt.message());
} }
logRxTxMessageText(QDateTime::currentDateTimeUtc(), lines.join(""), freq, true); logRxTxMessageText(QDateTime::currentDateTimeUtc(), lines.join(""), freq, true);
@ -6101,6 +6116,7 @@ bool MainWindow::prepareNextMessageFrame()
bool MainWindow::isFreqOffsetFree(int f, int bw){ bool MainWindow::isFreqOffsetFree(int f, int bw){
foreach(int offset, m_bandActivity.keys()){ foreach(int offset, m_bandActivity.keys()){
if(qAbs(offset - f) < bw){ if(qAbs(offset - f) < bw){
return false; return false;
} }
@ -6143,7 +6159,7 @@ void MainWindow::scheduleBacon(bool first){
// round to 15 second increment // round to 15 second increment
int secondsSinceEpoch = (timestamp.toMSecsSinceEpoch()/1000); 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); timestamp = timestamp.addSecs(delta);
// 25% of the time, switch intervals // 25% of the time, switch intervals
@ -6181,27 +6197,6 @@ void MainWindow::prepareBacon(){
return; 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; QStringList lines;
QString call = m_config.my_callsign(); QString call = m_config.my_callsign();
@ -6218,6 +6213,10 @@ void MainWindow::prepareBacon(){
// FT8Call Style // FT8Call Style
lines.append(QString("%1: BCN %2").arg(call).arg(grid)); lines.append(QString("%1: BCN %2").arg(call).arg(grid));
// Queue the beacon
enqueueMessage(PriorityLow, lines.join(QChar('\n')), currentFreq(), nullptr);
#if 0 #if 0
if(!m_callActivity.isEmpty()){ if(!m_callActivity.isEmpty()){
auto callsHeard = QSet<QString>::fromList(m_callActivity.keys()); auto callsHeard = QSet<QString>::fromList(m_callActivity.keys());
@ -6238,11 +6237,14 @@ void MainWindow::prepareBacon(){
} }
#endif #endif
#if 0
addMessageText(lines.join(QChar('\n'))); addMessageText(lines.join(QChar('\n')));
ui->startTxButton->setChecked(true); ui->startTxButton->setChecked(true);
scheduleBacon(false); scheduleBacon(false);
#endif
} }
@ -6284,10 +6286,6 @@ void MainWindow::toggleTx(bool start){
ui->startTxButton->setChecked(start); ui->startTxButton->setChecked(start);
} }
void MainWindow::splitAndSendNextMessage()
{
}
void MainWindow::on_rbNextFreeTextMsg_toggled (bool status) void MainWindow::on_rbNextFreeTextMsg_toggled (bool status)
{ {
if (status) { if (status) {
@ -9019,6 +9017,10 @@ void MainWindow::processCommandActivity() {
continue; continue;
} }
enqueueMessage(PriorityNormal, reply, d.freq, nullptr);
#if 0 #if 0
addMessageText(reply); addMessageText(reply);
@ -9055,8 +9057,58 @@ void MainWindow::processSpots() {
// Process spots to be sent... // 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) { void MainWindow::displayActivity(bool force) {
if (!m_rxDirty && !force) { if (!m_rxDisplayDirty && !force) {
return; return;
} }
@ -9065,6 +9117,8 @@ void MainWindow::displayActivity(bool force) {
// Call Activity // Call Activity
displayCallActivity(); displayCallActivity();
m_rxDisplayDirty = false;
} }
void MainWindow::displayBandActivity() { void MainWindow::displayBandActivity() {

View File

@ -23,6 +23,8 @@
#include <QFuture> #include <QFuture>
#include <QFutureWatcher> #include <QFutureWatcher>
#include <functional>
#include "AudioDevice.hpp" #include "AudioDevice.hpp"
#include "commons.h" #include "commons.h"
#include "Radio.hpp" #include "Radio.hpp"
@ -39,6 +41,7 @@
#include "MessageBox.hpp" #include "MessageBox.hpp"
#include "NetworkAccessManager.hpp" #include "NetworkAccessManager.hpp"
#include "qorderedmap.h" #include "qorderedmap.h"
#include "qpriorityqueue.h"
#include "varicode.h" #include "varicode.h"
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync #define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
@ -86,6 +89,9 @@ class MultiSettings;
class EqualizationToolsDialog; class EqualizationToolsDialog;
class DecodedText; class DecodedText;
using namespace std;
typedef std::function<void()> Callback;
class MainWindow : public QMainWindow class MainWindow : public QMainWindow
{ {
Q_OBJECT; Q_OBJECT;
@ -127,6 +133,7 @@ public slots:
void clearActivity(); void clearActivity();
int logRxTxMessageText(QDateTime date, QString text, int freq, bool tx, int block=-1); int logRxTxMessageText(QDateTime date, QString text, int freq, bool tx, int block=-1);
void addMessageText(QString text, bool clear=false); void addMessageText(QString text, bool clear=false);
void enqueueMessage(int priority, QString message, int freq, Callback c);
void resetMessage(); void resetMessage();
void resetMessageUI(); void resetMessageUI();
void restoreMessage(); void restoreMessage();
@ -203,7 +210,6 @@ private slots:
void on_txb6_clicked(); void on_txb6_clicked();
void on_startTxButton_toggled(bool checked); void on_startTxButton_toggled(bool checked);
void toggleTx(bool start); void toggleTx(bool start);
void splitAndSendNextMessage();
void on_rbNextFreeTextMsg_toggled (bool status); void on_rbNextFreeTextMsg_toggled (bool status);
void on_lookupButton_clicked(); void on_lookupButton_clicked();
void on_addButton_clicked(); void on_addButton_clicked();
@ -642,6 +648,14 @@ private:
QSet<QString> m_pfx; QSet<QString> m_pfx;
QSet<QString> m_sfx; QSet<QString> m_sfx;
struct FoxQSO
{
QString grid;
QString sent;
QString rcvd;
qint32 ncall;
};
struct CallDetail struct CallDetail
{ {
QString call; QString call;
@ -684,11 +698,35 @@ private:
}; };
bool m_rxDirty; bool m_rxDirty;
bool m_rxDisplayDirty;
int m_txFrameCount; int m_txFrameCount;
QString m_lastTxMessage; QString m_lastTxMessage;
QDateTime m_lastTxTime; QDateTime m_lastTxTime;
QQueue<QString> 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<PrioritizedMessage> m_txMessageQueue; // messages to be sent
QQueue<QString> m_txFrameQueue; // frames to be sent
QQueue<ActivityDetail> m_rxFrameQueue; QQueue<ActivityDetail> m_rxFrameQueue;
QQueue<CommandDetail> m_rxCommandQueue; QQueue<CommandDetail> m_rxCommandQueue;
QMap<QString, QString> m_compoundCallCache; // base callsign -> compound callsign QMap<QString, QString> m_compoundCallCache; // base callsign -> compound callsign
@ -722,7 +760,6 @@ private:
QQueue<QString> m_foxQSOinProgress; //QSOs in progress: Fox has sent a report QQueue<QString> m_foxQSOinProgress; //QSOs in progress: Fox has sent a report
QQueue<qint64> m_foxRateQueue; QQueue<qint64> m_foxRateQueue;
bool m_nextBeaconPaused = false; bool m_nextBeaconPaused = false;
QDateTime m_nextBeacon; QDateTime m_nextBeacon;
QDateTime m_dateTimeQSOOn; QDateTime m_dateTimeQSOOn;
@ -801,6 +838,7 @@ private:
void processBufferedActivity(); void processBufferedActivity();
void processCommandActivity(); void processCommandActivity();
void processSpots(); void processSpots();
void processTxQueue();
void displayActivity(bool force=false); void displayActivity(bool force=false);
void displayBandActivity(); void displayBandActivity();
void displayCallActivity(); void displayCallActivity();

View File

@ -117,8 +117,8 @@ public:
// like qqueue // like qqueue
inline void enqueue(const T &t) { push(t); } inline void enqueue(const T &t) { push(t); }
inline T dequeue() { T t = d.top(); d.pop(); return t; } inline T dequeue() { T t = d.top(); d.pop(); return t; }
inline T &head() { top(); } inline T &head() { return const_cast<T&>(top()); }
inline const T &head() const { top(); } inline const T &head() const { return top(); }
// stl compatibility // stl compatibility
typedef int size_type; typedef int size_type;