Parse "dx-call-1 RR73; dx-call-2 <de-call> +nn" messages in regular modes

This commit is contained in:
Bill Somerville 2021-10-29 22:27:32 +01:00
parent c0a5bad58a
commit 488c42b8a2
No known key found for this signature in database
GPG Key ID: D864B06D1E81618F
2 changed files with 105 additions and 58 deletions

View File

@ -11,7 +11,32 @@ extern "C" {
namespace namespace
{ {
QRegularExpression words_re {R"(^(?:(?<word1>(?:CQ|DE|QRZ)(?:\s?DX|\s(?:[A-Z]{1,4}|\d{3}))|[A-Z0-9/]+|\.{3})\s)(?:(?<word2>[A-Z0-9/]+)(?:\s(?<word3>[-+A-Z0-9]+)(?:\s(?<word4>(?:OOO|(?!RR73)[A-R]{2}[0-9]{2})))?)?)?)"}; QRegularExpression tokens_re {R"(
^
(?:(?<dual>[A-Z0-9/]+)\sRR73;\s)?
(?:
(?<word1>
(?:CQ|DE|QRZ)
(?:\s?DX|\s
(?:[A-Z]{1,4}|\d{3})
)
| [A-Z0-9/]+
|\.{3}
)\s
)
(?:
(?<word2>[A-Z0-9/]+)
(?:\s
(?<word3>[-+A-Z0-9]+)
(?:\s
(?<word4>
(?:OOO | (?!RR73)[A-R]{2}[0-9]{2})
)
)?
)?
)?
)"
, QRegularExpression::ExtendedPatternSyntaxOption};
} }
DecodedText::DecodedText (QString const& the_string) DecodedText::DecodedText (QString const& the_string)
@ -60,7 +85,9 @@ QStringList DecodedText::messageWords () const
// extract up to the first four message words // extract up to the first four message words
QString t=message_; QString t=message_;
if(t.left(4)=="TU; ") t=message_.mid(4,-1); if(t.left(4)=="TU; ") t=message_.mid(4,-1);
return words_re.match(t).capturedTexts(); auto res = tokens_re.match(t).capturedTexts();
qDebug () << "captured texts:" << res;
return res;
} }
// simple word split for free text messages // simple word split for free text messages
auto words = message_.split (' ', SkipEmptyParts); auto words = message_.split (' ', SkipEmptyParts);
@ -128,31 +155,37 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /
if (message_.size () < 1) return false; if (message_.size () < 1) return false;
QStringList const& w = message_.split(" ", SkipEmptyParts); QStringList const& w = message_.split(" ", SkipEmptyParts);
if (w.size () int offset {0};
&& is_standard_ && (w[0] == myBaseCall if (w.size () > 2)
|| w[0].endsWith ("/" + myBaseCall)
|| w[0].startsWith (myBaseCall + "/")
|| (w.size () > 1 && !dxBaseCall.isEmpty ()
&& (w[1] == dxBaseCall
|| w[1].endsWith ("/" + dxBaseCall)
|| w[1].startsWith (dxBaseCall + "/")))))
{ {
QString tt=""; if ("RR73;" == w[1] && w.size () > 3)
if(w.size() > 2) tt=w[2];
bool ok;
auto i1=tt.toInt(&ok);
if (ok and i1>=-50 and i1<50)
{ {
report = tt; offset = 2;
} }
else if (is_standard_ && (w[offset] == myBaseCall
|| w[offset].endsWith ("/" + myBaseCall)
|| w[offset].startsWith (myBaseCall + "/")
|| (w.size () > offset + 1 && !dxBaseCall.isEmpty ()
&& (w[offset + 1] == dxBaseCall
|| w[offset + 1].endsWith ("/" + dxBaseCall)
|| w[offset + 1].startsWith (dxBaseCall + "/")))))
{ {
if (tt.mid(0,1)=="R") bool ok;
auto tt = w[offset + 2];
auto i1=tt.toInt(&ok);
if (ok and i1>=-50 and i1<50)
{ {
i1=tt.mid(1).toInt(&ok); report = tt;
if(ok and i1>=-50 and i1<50) }
else
{
if (tt.mid(0,1)=="R")
{ {
report = tt.mid(1); i1=tt.mid(1).toInt(&ok);
if(ok and i1>=-50 and i1<50)
{
report = tt.mid(1);
}
} }
} }
} }
@ -163,7 +196,7 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /
// get the first text word, usually the call // get the first text word, usually the call
QString DecodedText::call() const QString DecodedText::call() const
{ {
return words_re.match (message_).captured ("word1"); return tokens_re.match (message_).captured ("word1");
} }
// get the second word, most likely the de call and the third word, most likely grid // get the second word, most likely the de call and the third word, most likely grid
@ -175,7 +208,7 @@ void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid) const
{ {
msg = msg.mid (p + 2); msg = msg.mid (p + 2);
} }
auto const& match = words_re.match (msg); auto const& match = tokens_re.match (msg);
call = match.captured ("word2"); call = match.captured ("word2");
grid = match.captured ("word3"); grid = match.captured ("word3");
if ("R" == grid) grid = match.captured ("word4"); if ("R" == grid) grid = match.captured ("word4");

View File

@ -3643,7 +3643,7 @@ void MainWindow::auto_sequence (DecodedText const& message, unsigned start_toler
auto is_73 = message_words.filter (QRegularExpression {"^(73|RR73)$"}).size(); auto is_73 = message_words.filter (QRegularExpression {"^(73|RR73)$"}).size();
bool is_OK=false; bool is_OK=false;
if(m_mode=="MSK144" and message.clean_string ().indexOf(ui->dxCallEntry->text()+" R ")>0) is_OK=true; if(m_mode=="MSK144" and message.clean_string ().indexOf(ui->dxCallEntry->text()+" R ")>0) is_OK=true;
if (message_words.size () > 2 && (message.isStandardMessage() || (is_73 or is_OK))) { if (message_words.size () > 3 && (message.isStandardMessage() || (is_73 or is_OK))) {
auto df = message.frequencyOffset (); auto df = message.frequencyOffset ();
auto within_tolerance = (qAbs (ui->RxFreqSpinBox->value () - df) <= int (start_tolerance) auto within_tolerance = (qAbs (ui->RxFreqSpinBox->value () - df) <= int (start_tolerance)
|| qAbs (ui->TxFreqSpinBox->value () - df) <= int (start_tolerance)); || qAbs (ui->TxFreqSpinBox->value () - df) <= int (start_tolerance));
@ -3675,27 +3675,29 @@ void MainWindow::auto_sequence (DecodedText const& message, unsigned start_toler
if (m_auto if (m_auto
&& (m_QSOProgress==REPLYING or (!ui->tx1->isEnabled () and m_QSOProgress==REPORT)) && (m_QSOProgress==REPLYING or (!ui->tx1->isEnabled () and m_QSOProgress==REPORT))
&& qAbs (ui->TxFreqSpinBox->value () - df) <= int (stop_tolerance) && qAbs (ui->TxFreqSpinBox->value () - df) <= int (stop_tolerance)
&& message_words.at (1) != "DE" && message_words.at (2) != "DE"
&& !message_words.at (1).contains (QRegularExpression {"(^(CQ|QRZ))|" + m_baseCall}) && !message_words.at (2).contains (QRegularExpression {"(^(CQ|QRZ))|" + m_baseCall})
&& message_words.at (2).contains (Radio::base_callsign (ui->dxCallEntry->text ()))) { && message_words.at (3).contains (Radio::base_callsign (ui->dxCallEntry->text ()))) {
// auto stop to avoid accidental QRM // auto stop to avoid accidental QRM
ui->stopTxButton->click (); // halt any transmission ui->stopTxButton->click (); // halt any transmission
} else if (m_auto // transmit allowed } else if (m_auto // transmit allowed
&& ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isEnabled () && ui->cbAutoSeq->isChecked () // auto-sequencing allowed && ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isEnabled () && ui->cbAutoSeq->isChecked () // auto-sequencing allowed
&& ((!m_bCallingCQ // not calling CQ/QRZ && ((!m_bCallingCQ // not calling CQ/QRZ
&& !m_sentFirst73 // not finished QSO && !m_sentFirst73 // not finished QSO
&& ((message_words.at (1).contains (m_baseCall) && ((message_words.at (2).contains (m_baseCall)
// being called and not already in a QSO // being called and not already in a QSO
&& (message_words.at(2).contains(Radio::base_callsign(ui->dxCallEntry->text())) or bEU_VHF)) && (message_words.at(3).contains(Radio::base_callsign(ui->dxCallEntry->text()))
// type 2 compound replies or bEU_VHF))
|| (within_tolerance && || message_words.at(1) == m_baseCall // <de-call> RR73; ...
(acceptable_73 || // type 2 compound replies
("DE" == message_words.at (1) && || (within_tolerance &&
w2.contains(Radio::base_callsign (m_hisCall))))))) (acceptable_73 ||
|| (m_bCallingCQ && m_bAutoReply ("DE" == message_words.at (2) &&
// look for type 2 compound call replies on our Tx and Rx offsets w2.contains(Radio::base_callsign (m_hisCall)))))))
&& ((within_tolerance && "DE" == message_words.at (1)) || (m_bCallingCQ && m_bAutoReply
|| message_words.at (1).contains (m_baseCall))))) { // look for type 2 compound call replies on our Tx and Rx offsets
&& ((within_tolerance && "DE" == message_words.at (2))
|| message_words.at (2).contains (m_baseCall))))) {
if(SpecOp::FOX != m_config.special_op_id()) processMessage (message); if(SpecOp::FOX != m_config.special_op_id()) processMessage (message);
} }
} }
@ -4806,7 +4808,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
ui->txFirstCheckBox->setChecked(m_txFirst); ui->txFirstCheckBox->setChecked(m_txFirst);
auto const& message_words = message.messageWords (); auto const& message_words = message.messageWords ();
if (message_words.size () < 2) return; if (message_words.size () < 3) return;
QString hiscall; QString hiscall;
QString hisgrid; QString hisgrid;
@ -4824,7 +4826,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
QStringList w=message.clean_string ().mid(22).remove("<").remove(">").split(" ",SkipEmptyParts); QStringList w=message.clean_string ().mid(22).remove("<").remove(">").split(" ",SkipEmptyParts);
int nw=w.size(); int nw=w.size();
if(nw>=4) { if(nw>=4) {
if(message_words.size()<3) return; if(message_words.size()<4) return;
int n=w.at(nw-2).toInt(); int n=w.at(nw-2).toInt();
if(n>=520001 and n<=592047) { if(n>=520001 and n<=592047) {
hiscall=w.at(1); hiscall=w.at(1);
@ -4847,7 +4849,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
// ignore calls by other hounds // ignore calls by other hounds
if (SpecOp::HOUND == m_config.special_op_id() if (SpecOp::HOUND == m_config.special_op_id()
&& message.messageWords ().indexOf (QRegularExpression {R"(R\+-[0-9]+)"}) >= 0) && message.messageWords ().indexOf (QRegularExpression {R"(R\+-[0-9]+)"}) >= 1)
{ {
return; return;
} }
@ -4926,22 +4928,22 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
MessageBox::information_message (this, tr ("Should you switch to RTTY contest mode?")); MessageBox::information_message (this, tr ("Should you switch to RTTY contest mode?"));
} }
if(SpecOp::EU_VHF==m_config.special_op_id() and message_words.at(1).contains(m_baseCall) and if(SpecOp::EU_VHF==m_config.special_op_id() and message_words.at(2).contains(m_baseCall) and
(!message_words.at(2).contains(qso_partner_base_call)) and (!m_bDoubleClicked)) { (!message_words.at(3).contains(qso_partner_base_call)) and (!m_bDoubleClicked)) {
return; return;
} }
bool bContestOK=(m_mode=="FT4" or m_mode=="FT8" or m_mode=="Q65" or m_mode=="MSK144"); bool bContestOK=(m_mode=="FT4" or m_mode=="FT8" or m_mode=="Q65" or m_mode=="MSK144");
if(message_words.size () > 3 // enough fields for a normal message if(message_words.size () > 4 // enough fields for a normal message
&& (message_words.at(1).contains(m_baseCall) || "DE" == message_words.at(1)) && (message_words.at(2).contains(m_baseCall) || "DE" == message_words.at(2))
&& (message_words.at(2).contains(qso_partner_base_call) or m_bDoubleClicked && (message_words.at(3).contains(qso_partner_base_call) or m_bDoubleClicked
or bEU_VHF_w2 or (m_QSOProgress==CALLING))) { or bEU_VHF_w2 or (m_QSOProgress==CALLING))) {
if(message_words.at(3).contains(grid_regexp) and SpecOp::EU_VHF!=m_config.special_op_id()) { if(message_words.at(4).contains(grid_regexp) and SpecOp::EU_VHF!=m_config.special_op_id()) {
if((SpecOp::NA_VHF==m_config.special_op_id() or SpecOp::WW_DIGI==m_config.special_op_id()) and bContestOK){ if((SpecOp::NA_VHF==m_config.special_op_id() or SpecOp::WW_DIGI==m_config.special_op_id()) and bContestOK){
setTxMsg(3); setTxMsg(3);
m_QSOProgress=ROGER_REPORT; m_QSOProgress=ROGER_REPORT;
} else { } else {
if(m_mode=="JT65" and message_words.size()>4 and message_words.at(4)=="OOO") { if(m_mode=="JT65" and message_words.size()>5 and message_words.at(5)=="OOO") {
setTxMsg(3); setTxMsg(3);
m_QSOProgress=ROGER_REPORT; m_QSOProgress=ROGER_REPORT;
} else { } else {
@ -4981,7 +4983,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
m_QSOProgress=ROGER_REPORT; m_QSOProgress=ROGER_REPORT;
} }
} else { // no grid on end of msg } else { // no grid on end of msg
auto const& word_3 = message_words.at (3); auto const& word_3 = message_words.at (4);
auto word_3_as_number = word_3.toInt (); auto word_3_as_number = word_3.toInt ();
if (("RRR" == word_3 if (("RRR" == word_3
|| (word_3_as_number == 73 && ROGERS == m_QSOProgress) || (word_3_as_number == 73 && ROGERS == m_QSOProgress)
@ -5103,17 +5105,29 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
} }
} }
} }
else if (5 == message_words.size ()
&& m_baseCall == message_words.at (1)) {
// dual Fox style message, possibly from MSHV
if (m_config.prompt_to_log() || m_config.autoLog()) {
logQSOTimer.start(0);
}
else {
cease_auto_Tx_after_QSO ();
}
m_ntx=6;
ui->txrb6->setChecked(true);
}
else if (m_QSOProgress >= ROGERS else if (m_QSOProgress >= ROGERS
&& message_words.size () > 2 && message_words.at (1).contains (m_baseCall) && message_words.size () > 3 && message_words.at (2).contains (m_baseCall)
&& message_words.at (2) == "73") { && message_words.at (3) == "73") {
// 73 back to compound call holder // 73 back to compound call holder
m_ntx=5; m_ntx=5;
ui->txrb5->setChecked(true); ui->txrb5->setChecked(true);
m_QSOProgress = SIGNOFF; m_QSOProgress = SIGNOFF;
} }
else if (!(m_bAutoReply && (m_QSOProgress > CALLING))) { else if (!(m_bAutoReply && (m_QSOProgress > CALLING))) {
if ((message_words.size () > 4 && message_words.at (1).contains (m_baseCall) if ((message_words.size () > 5 && message_words.at (2).contains (m_baseCall)
&& message_words.at (4) == "OOO")) { && message_words.at (5) == "OOO")) {
// EME short code report or MSK144/FT8 contest mode reply, send back Tx3 // EME short code report or MSK144/FT8 contest mode reply, send back Tx3
m_ntx=3; m_ntx=3;
m_QSOProgress = ROGER_REPORT; m_QSOProgress = ROGER_REPORT;
@ -5136,7 +5150,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
return; return;
} }
} }
else if (firstcall == "DE" && message_words.size () > 3 && message_words.at (3) == "73") { else if (firstcall == "DE" && message_words.size () > 4 && message_words.at (4) == "73") {
if (m_QSOProgress >= ROGERS && base_call == qso_partner_base_call && m_currentMessageType) { if (m_QSOProgress >= ROGERS && base_call == qso_partner_base_call && m_currentMessageType) {
// 73 back to compound call holder // 73 back to compound call holder
m_ntx=5; m_ntx=5;