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