Initial cut of relay
This commit is contained in:
parent
308a45efe0
commit
15ee95360f
143
mainwindow.cpp
143
mainwindow.cpp
@ -7,6 +7,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <fftw3.h>
|
#include <fftw3.h>
|
||||||
|
#include <QInputDialog>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QRegExpValidator>
|
#include <QRegExpValidator>
|
||||||
#include <QRegExp>
|
#include <QRegExp>
|
||||||
@ -9349,6 +9350,7 @@ void MainWindow::processCommandActivity() {
|
|||||||
if (d.cmd == "?") {
|
if (d.cmd == "?") {
|
||||||
reply = QString("%1 SNR %2").arg(d.from).arg(Varicode::formatSNR(d.snr));
|
reply = QString("%1 SNR %2").arg(d.from).arg(Varicode::formatSNR(d.snr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// QUERIED QTH
|
// QUERIED QTH
|
||||||
else if (d.cmd == "@" && !isAllCall) {
|
else if (d.cmd == "@" && !isAllCall) {
|
||||||
QString qth = m_config.my_qth();
|
QString qth = m_config.my_qth();
|
||||||
@ -9358,6 +9360,7 @@ void MainWindow::processCommandActivity() {
|
|||||||
|
|
||||||
reply = QString("%1 QTH %2").arg(d.from).arg(qth);
|
reply = QString("%1 QTH %2").arg(d.from).arg(qth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// QUERIED GRID
|
// QUERIED GRID
|
||||||
else if (d.cmd == "^" && !isAllCall) {
|
else if (d.cmd == "^" && !isAllCall) {
|
||||||
QString grid = m_config.my_grid();
|
QString grid = m_config.my_grid();
|
||||||
@ -9367,10 +9370,12 @@ void MainWindow::processCommandActivity() {
|
|||||||
|
|
||||||
reply = QString("%1 GRID %2").arg(d.from).arg(grid);
|
reply = QString("%1 GRID %2").arg(d.from).arg(grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
// QUERIED STATION MESSAGE
|
// QUERIED STATION MESSAGE
|
||||||
else if (d.cmd == "&" && !isAllCall) {
|
else if (d.cmd == "&" && !isAllCall) {
|
||||||
reply = QString("%1 QTC %2").arg(d.from).arg(m_config.my_station());
|
reply = QString("%1 QTC %2").arg(d.from).arg(m_config.my_station());
|
||||||
}
|
}
|
||||||
|
|
||||||
// QUERIED STATIONS HEARD
|
// QUERIED STATIONS HEARD
|
||||||
else if (d.cmd == "$" && !isAllCall) {
|
else if (d.cmd == "$" && !isAllCall) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -9406,14 +9411,62 @@ void MainWindow::processCommandActivity() {
|
|||||||
lines.prepend(QString("<%1 HEARING>").arg(m_config.my_callsign()));
|
lines.prepend(QString("<%1 HEARING>").arg(m_config.my_callsign()));
|
||||||
reply = lines.join('\n');
|
reply = lines.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROCESS RETRANSMIT
|
// PROCESS RETRANSMIT
|
||||||
else if (d.cmd == "|" && !isAllCall) {
|
else if (d.cmd == "|" && !isAllCall) {
|
||||||
// TODO: jsherer - perhaps parse d.text and ensure it is a valid message as well as prefix it with our call...
|
// TODO: jsherer - perhaps parse d.text and ensure it is a valid message as well as prefix it with our call...
|
||||||
|
|
||||||
reply = QString("%1 ACK\n%2 DE %1").arg(d.from).arg(d.text);
|
reply = QString("%1 ACK\n%2 DE %1").arg(d.from).arg(d.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PROCESS RELAY
|
||||||
|
else if (d.cmd == ">" && !isAllCall) {
|
||||||
|
|
||||||
|
// 1. see if there are any more hops to process
|
||||||
|
// 2. if so, forward
|
||||||
|
// 3. otherwise, display alert
|
||||||
|
|
||||||
|
QString callToPattern = {R"((?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[A-Z0-9]{1,4})?[>])\b)"};
|
||||||
|
QRegularExpression re(callToPattern);
|
||||||
|
auto match = re.match(d.text);
|
||||||
|
|
||||||
|
// if the text starts with a callsign, relay.
|
||||||
|
if(match.hasMatch()){
|
||||||
|
reply = QString("%1 DE %2").arg(d.text).arg(d.from);
|
||||||
|
|
||||||
|
// otherwise, as long as we're not an ACK...alert the user and either send an ACK or Message
|
||||||
|
} else if(!d.text.startsWith("ACK DE")) {
|
||||||
|
QStringList calls;
|
||||||
|
QString callDePattern = {R"(\sDE\s(?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[A-Z0-9]{1,4})?)\b)"};
|
||||||
|
QRegularExpression re(callDePattern);
|
||||||
|
auto iter = re.globalMatch(d.text);
|
||||||
|
while(iter.hasNext()){
|
||||||
|
auto match = iter.next();
|
||||||
|
calls.prepend(match.captured("callsign"));
|
||||||
|
}
|
||||||
|
calls.prepend(d.from);
|
||||||
|
|
||||||
|
processAlertReplyForCommand(d, calls.join('>'), ">");
|
||||||
|
|
||||||
|
//reply = QString("%1>ACK").arg(calls.join('>'));
|
||||||
|
//bool ok = false;
|
||||||
|
//reply = QString("%1>%2").arg(calls.join('>')).arg(ok && !text.isEmpty() ? text : "ACK");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
KN4CRD: W0FW>N0JDS>OH8STN> Hello Julian...
|
||||||
|
W0FW: N0JDS>OH8STN> Hello Julian... <KN4CRD
|
||||||
|
N0JDS: OH8STN> Hello Julian... <KN4CRD<W0FW
|
||||||
|
|
||||||
|
OH8STN: N0JDS>W0FW>KN4CRD> ACK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// PROCESS BUFFERED MESSAGE
|
// PROCESS BUFFERED MESSAGE
|
||||||
else if (d.cmd == "#" && !isAllCall) {
|
else if (d.cmd == "#" && !isAllCall) {
|
||||||
|
|
||||||
// open file /save/messages/[callsign].txt and append a message log entry...
|
// open file /save/messages/[callsign].txt and append a message log entry...
|
||||||
QFile f(QDir::toNativeSeparators(m_config.writeable_data_dir ().absolutePath()) + QString("/save/messages/%1.txt").arg(Radio::base_callsign(d.from)));
|
QFile f(QDir::toNativeSeparators(m_config.writeable_data_dir ().absolutePath()) + QString("/save/messages/%1.txt").arg(Radio::base_callsign(d.from)));
|
||||||
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
|
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
|
||||||
@ -9431,10 +9484,12 @@ void MainWindow::processCommandActivity() {
|
|||||||
|
|
||||||
reply = QString("%1 ACK").arg(d.from);
|
reply = QString("%1 ACK").arg(d.from);
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROCESS AGN
|
// PROCESS AGN
|
||||||
else if (d.cmd == " AGN?" && !isAllCall && !m_lastTxMessage.isEmpty()) {
|
else if (d.cmd == " AGN?" && !isAllCall && !m_lastTxMessage.isEmpty()) {
|
||||||
reply = m_lastTxMessage;
|
reply = m_lastTxMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PROCESS BUFFERED QSO QUERY
|
// PROCESS BUFFERED QSO QUERY
|
||||||
else if (d.cmd == " QSO"){
|
else if (d.cmd == " QSO"){
|
||||||
auto who = d.text;
|
auto who = d.text;
|
||||||
@ -9462,6 +9517,15 @@ void MainWindow::processCommandActivity() {
|
|||||||
}
|
}
|
||||||
reply = replies.join("\n");
|
reply = replies.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PROCESS BUFFERED APRS:
|
||||||
|
else if(d.cmd == " APRS:" && m_config.spot_to_reporting_networks() && m_aprsClient->isPasscodeValid()){
|
||||||
|
m_aprsClient->enqueueThirdParty(Radio::base_callsign(d.from), d.text);
|
||||||
|
|
||||||
|
// make sure this is explicit
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// PROCESS BUFFERED QTH
|
// PROCESS BUFFERED QTH
|
||||||
else if (d.cmd == " GRID"){
|
else if (d.cmd == " GRID"){
|
||||||
// 1. parse grids
|
// 1. parse grids
|
||||||
@ -9478,42 +9542,15 @@ void MainWindow::processCommandActivity() {
|
|||||||
logCallActivity(cd, true);
|
logCallActivity(cd, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure this is explicit
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// PROCESS APRS
|
|
||||||
else if(d.cmd == " APRS:" && m_config.spot_to_reporting_networks() && m_aprsClient->isPasscodeValid()){
|
|
||||||
m_aprsClient->enqueueThirdParty(Radio::base_callsign(d.from), d.text);
|
|
||||||
reply = QString("%1 ACK").arg(d.from);
|
|
||||||
}
|
|
||||||
// PROCESS ALERT
|
// PROCESS ALERT
|
||||||
else if (d.cmd == "!" && !isAllCall) {
|
else if (d.cmd == "!" && !isAllCall) {
|
||||||
QMessageBox * msgBox = new QMessageBox(this);
|
|
||||||
msgBox->setIcon(QMessageBox::Information);
|
|
||||||
|
|
||||||
auto header = QString("Message from %3 at %1 (%2):");
|
// create alert dialog
|
||||||
header = header.arg(d.utcTimestamp.time().toString());
|
processAlertReplyForCommand(d, d.from, " ");
|
||||||
header = header.arg(d.freq);
|
|
||||||
header = header.arg(d.from);
|
|
||||||
msgBox->setText(header);
|
|
||||||
msgBox->setInformativeText(d.text);
|
|
||||||
|
|
||||||
auto ab = msgBox->addButton("ACK", QMessageBox::AcceptRole);
|
|
||||||
auto db = msgBox->addButton("Discard", QMessageBox::NoRole);
|
|
||||||
|
|
||||||
connect(msgBox, & QMessageBox::buttonClicked, this, [this, d, db, ab](QAbstractButton * btn) {
|
|
||||||
if (btn != ab) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
enqueueMessage(PriorityHigh, QString("%1 ACK").arg(d.from), d.freq, nullptr);
|
|
||||||
});
|
|
||||||
|
|
||||||
auto wav = m_config.sound_am_path();
|
|
||||||
if(!wav.isEmpty()){
|
|
||||||
QSound::play(wav);
|
|
||||||
}
|
|
||||||
|
|
||||||
msgBox->show();
|
|
||||||
|
|
||||||
// make sure this is explicit
|
// make sure this is explicit
|
||||||
continue;
|
continue;
|
||||||
@ -9536,6 +9573,48 @@ void MainWindow::processCommandActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::processAlertReplyForCommand(CommandDetail d, QString from, QString cmd){
|
||||||
|
QMessageBox * msgBox = new QMessageBox(this);
|
||||||
|
msgBox->setIcon(QMessageBox::Information);
|
||||||
|
|
||||||
|
auto header = QString("Message from %3 at %1 (%2):");
|
||||||
|
header = header.arg(d.utcTimestamp.time().toString());
|
||||||
|
header = header.arg(d.freq);
|
||||||
|
header = header.arg(d.from);
|
||||||
|
msgBox->setText(header);
|
||||||
|
msgBox->setInformativeText(d.text);
|
||||||
|
|
||||||
|
auto ab = msgBox->addButton("ACK", QMessageBox::AcceptRole);
|
||||||
|
auto rb = msgBox->addButton("Reply", QMessageBox::AcceptRole);
|
||||||
|
auto db = msgBox->addButton("Discard", QMessageBox::NoRole);
|
||||||
|
|
||||||
|
connect(msgBox, & QMessageBox::buttonClicked, this, [this, cmd, from, d, db, rb, ab](QAbstractButton * btn) {
|
||||||
|
if (btn == db) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btn == ab){
|
||||||
|
enqueueMessage(PriorityHigh, QString("%1%2ACK").arg(from).arg(cmd), d.freq, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(btn == rb){
|
||||||
|
bool ok = false;
|
||||||
|
QString text = QInputDialog::getMultiLineText(this, "Message Reply", QString("Message to send to %1:").arg(from), "", &ok);
|
||||||
|
if(ok && !text.isEmpty()){
|
||||||
|
enqueueMessage(PriorityHigh, QString("%1%2%3").arg(from).arg(cmd).arg(text), d.freq, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
auto wav = m_config.sound_am_path();
|
||||||
|
if(!wav.isEmpty()){
|
||||||
|
QSound::play(wav);
|
||||||
|
}
|
||||||
|
|
||||||
|
msgBox->show();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::processSpots() {
|
void MainWindow::processSpots() {
|
||||||
if(!ui->spotButton->isChecked()){
|
if(!ui->spotButton->isChecked()){
|
||||||
m_rxCallQueue.clear();
|
m_rxCallQueue.clear();
|
||||||
|
@ -872,6 +872,7 @@ private:
|
|||||||
void processCompoundActivity();
|
void processCompoundActivity();
|
||||||
void processBufferedActivity();
|
void processBufferedActivity();
|
||||||
void processCommandActivity();
|
void processCommandActivity();
|
||||||
|
void processAlertReplyForCommand(CommandDetail d, QString from, QString cmd);
|
||||||
void processSpots();
|
void processSpots();
|
||||||
void processTxQueue();
|
void processTxQueue();
|
||||||
void displayActivity(bool force=false);
|
void displayActivity(bool force=false);
|
||||||
|
@ -45,7 +45,7 @@ QMap<QString, int> directed_cmds = {
|
|||||||
{"&", 2 }, // query station message
|
{"&", 2 }, // query station message
|
||||||
{"$", 3 }, // query station(s) heard
|
{"$", 3 }, // query station(s) heard
|
||||||
{"^", 4 }, // query grid
|
{"^", 4 }, // query grid
|
||||||
// {"%" 5 }, // unused
|
{">", 5 }, // relay message
|
||||||
{"|", 6 }, // retransmit message
|
{"|", 6 }, // retransmit message
|
||||||
{"!", 7 }, // alert message
|
{"!", 7 }, // alert message
|
||||||
{"#", 8 }, // all or nothing message
|
{"#", 8 }, // all or nothing message
|
||||||
@ -78,11 +78,12 @@ QMap<QString, int> directed_cmds = {
|
|||||||
{" ", 31 }, // send freetext
|
{" ", 31 }, // send freetext
|
||||||
};
|
};
|
||||||
|
|
||||||
QSet<int> allowed_cmds = {0, 1, 2, 3, 4, /*5,*/ 6, 7, 8, /*...*/ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, /*24,*/ 25, 26, 27, 28, 29, 30, 31};
|
QSet<int> allowed_cmds = {0, 1, 2, 3, 4, 5, 6, 7, 8, /*...*/ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, /*24,*/ 25, 26, 27, 28, 29, 30, 31};
|
||||||
|
|
||||||
QSet<int> buffered_cmds = {6, 7, 8, 13, 14, 15};
|
QSet<int> buffered_cmds = {5, 6, 7, 8, 13, 14, 15};
|
||||||
|
|
||||||
QMap<int, int> checksum_cmds = {
|
QMap<int, int> checksum_cmds = {
|
||||||
|
{ 5, 16 },
|
||||||
{ 6, 16 },
|
{ 6, 16 },
|
||||||
{ 7, 16 },
|
{ 7, 16 },
|
||||||
{ 8, 32 },
|
{ 8, 32 },
|
||||||
@ -92,7 +93,7 @@ QMap<int, int> checksum_cmds = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
QString callsign_pattern = QString("(?<callsign>[A-Z0-9/]+)");
|
QString callsign_pattern = QString("(?<callsign>[A-Z0-9/]+)");
|
||||||
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|ACK|73|YES|NO|SNR|QSL[?]?|RR|HEARING|HW CPY[?]|FB|QTH|QTC|GRID|APRS[:]|QSO|[?@&$%|!#^ ]))?");
|
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|ACK|73|YES|NO|SNR|QSL[?]?|RR|HEARING|HW CPY[?]|FB|QTH|QTC|GRID|APRS[:]|QSO|[?@&$%|!#^> ]))?");
|
||||||
QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?");
|
QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?");
|
||||||
QString optional_extended_grid_pattern = QString("^(?<grid>\\s?(?:[A-R]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*))?");
|
QString optional_extended_grid_pattern = QString("^(?<grid>\\s?(?:[A-R]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*))?");
|
||||||
QString optional_num_pattern = QString("(?<num>(?<=SNR|HEARING)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
|
QString optional_num_pattern = QString("(?<num>(?<=SNR|HEARING)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
|
||||||
|
Loading…
Reference in New Issue
Block a user