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:
parent
f0de2f2ba1
commit
62c449669f
@ -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){
|
||||||
|
110
mainwindow.cpp
110
mainwindow.cpp
@ -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() {
|
||||||
|
44
mainwindow.h
44
mainwindow.h
@ -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();
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user