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){
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){

View File

@ -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<QString>::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() {

View File

@ -23,6 +23,8 @@
#include <QFuture>
#include <QFutureWatcher>
#include <functional>
#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<void()> 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<QString> m_pfx;
QSet<QString> 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<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<CommandDetail> m_rxCommandQueue;
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<qint64> 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();

View File

@ -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<T&>(top()); }
inline const T &head() const { return top(); }
// stl compatibility
typedef int size_type;