diff --git a/Decoder/decodedtext.cpp b/Decoder/decodedtext.cpp index bc7587f6b..8f7f95738 100644 --- a/Decoder/decodedtext.cpp +++ b/Decoder/decodedtext.cpp @@ -11,7 +11,32 @@ extern "C" { namespace { - QRegularExpression words_re {R"(^(?:(?(?:CQ|DE|QRZ)(?:\s?DX|\s(?:[A-Z]{1,4}|\d{3}))|[A-Z0-9/]+|\.{3})\s)(?:(?[A-Z0-9/]+)(?:\s(?[-+A-Z0-9]+)(?:\s(?(?:OOO|(?!RR73)[A-R]{2}[0-9]{2})))?)?)?)"}; + QRegularExpression tokens_re {R"( +^ + (?:(?[A-Z0-9/]+)\sRR73;\s)? + (?: + (? + (?:CQ|DE|QRZ) + (?:\s?DX|\s + (?:[A-Z]{1,4}|\d{3}) + ) + | [A-Z0-9/]+ + |\.{3} + )\s + ) + (?: + (?[A-Z0-9/]+) + (?:\s + (?[-+A-Z0-9]+) + (?:\s + (? + (?:OOO | (?!RR73)[A-R]{2}[0-9]{2}) + ) + )? + )? + )? +)" + , QRegularExpression::ExtendedPatternSyntaxOption}; } DecodedText::DecodedText (QString const& the_string) @@ -60,7 +85,9 @@ QStringList DecodedText::messageWords () const // extract up to the first four message words QString t=message_; 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 auto words = message_.split (' ', SkipEmptyParts); @@ -128,31 +155,37 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, / if (message_.size () < 1) return false; QStringList const& w = message_.split(" ", SkipEmptyParts); - if (w.size () - && is_standard_ && (w[0] == myBaseCall - || w[0].endsWith ("/" + myBaseCall) - || w[0].startsWith (myBaseCall + "/") - || (w.size () > 1 && !dxBaseCall.isEmpty () - && (w[1] == dxBaseCall - || w[1].endsWith ("/" + dxBaseCall) - || w[1].startsWith (dxBaseCall + "/"))))) + int offset {0}; + if (w.size () > 2) { - QString tt=""; - if(w.size() > 2) tt=w[2]; - bool ok; - auto i1=tt.toInt(&ok); - if (ok and i1>=-50 and i1<50) + if ("RR73;" == w[1] && w.size () > 3) { - 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); - if(ok and i1>=-50 and i1<50) + report = tt; + } + 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 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 @@ -175,7 +208,7 @@ void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid) const { msg = msg.mid (p + 2); } - auto const& match = words_re.match (msg); + auto const& match = tokens_re.match (msg); call = match.captured ("word2"); grid = match.captured ("word3"); if ("R" == grid) grid = match.captured ("word4"); diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 5502f69f5..70a6f3d2a 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3643,7 +3643,7 @@ void MainWindow::auto_sequence (DecodedText const& message, unsigned start_toler auto is_73 = message_words.filter (QRegularExpression {"^(73|RR73)$"}).size(); bool is_OK=false; 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 within_tolerance = (qAbs (ui->RxFreqSpinBox->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 && (m_QSOProgress==REPLYING or (!ui->tx1->isEnabled () and m_QSOProgress==REPORT)) && qAbs (ui->TxFreqSpinBox->value () - df) <= int (stop_tolerance) - && message_words.at (1) != "DE" - && !message_words.at (1).contains (QRegularExpression {"(^(CQ|QRZ))|" + m_baseCall}) - && message_words.at (2).contains (Radio::base_callsign (ui->dxCallEntry->text ()))) { + && message_words.at (2) != "DE" + && !message_words.at (2).contains (QRegularExpression {"(^(CQ|QRZ))|" + m_baseCall}) + && message_words.at (3).contains (Radio::base_callsign (ui->dxCallEntry->text ()))) { // auto stop to avoid accidental QRM ui->stopTxButton->click (); // halt any transmission } else if (m_auto // transmit allowed - && ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isEnabled () && ui->cbAutoSeq->isChecked () // auto-sequencing allowed - && ((!m_bCallingCQ // not calling CQ/QRZ - && !m_sentFirst73 // not finished QSO - && ((message_words.at (1).contains (m_baseCall) - // being called and not already in a QSO - && (message_words.at(2).contains(Radio::base_callsign(ui->dxCallEntry->text())) or bEU_VHF)) - // type 2 compound replies - || (within_tolerance && - (acceptable_73 || - ("DE" == message_words.at (1) && - w2.contains(Radio::base_callsign (m_hisCall))))))) - || (m_bCallingCQ && m_bAutoReply - // look for type 2 compound call replies on our Tx and Rx offsets - && ((within_tolerance && "DE" == message_words.at (1)) - || message_words.at (1).contains (m_baseCall))))) { + && ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isEnabled () && ui->cbAutoSeq->isChecked () // auto-sequencing allowed + && ((!m_bCallingCQ // not calling CQ/QRZ + && !m_sentFirst73 // not finished QSO + && ((message_words.at (2).contains (m_baseCall) + // being called and not already in a QSO + && (message_words.at(3).contains(Radio::base_callsign(ui->dxCallEntry->text())) + or bEU_VHF)) + || message_words.at(1) == m_baseCall // RR73; ... + // type 2 compound replies + || (within_tolerance && + (acceptable_73 || + ("DE" == message_words.at (2) && + w2.contains(Radio::base_callsign (m_hisCall))))))) + || (m_bCallingCQ && m_bAutoReply + // 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); } } @@ -4806,7 +4808,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie ui->txFirstCheckBox->setChecked(m_txFirst); auto const& message_words = message.messageWords (); - if (message_words.size () < 2) return; + if (message_words.size () < 3) return; QString hiscall; 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); int nw=w.size(); if(nw>=4) { - if(message_words.size()<3) return; + if(message_words.size()<4) return; int n=w.at(nw-2).toInt(); if(n>=520001 and n<=592047) { hiscall=w.at(1); @@ -4847,7 +4849,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie // ignore calls by other hounds 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; } @@ -4926,22 +4928,22 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie 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 - (!message_words.at(2).contains(qso_partner_base_call)) and (!m_bDoubleClicked)) { + if(SpecOp::EU_VHF==m_config.special_op_id() and message_words.at(2).contains(m_baseCall) and + (!message_words.at(3).contains(qso_partner_base_call)) and (!m_bDoubleClicked)) { return; } 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 - && (message_words.at(1).contains(m_baseCall) || "DE" == message_words.at(1)) - && (message_words.at(2).contains(qso_partner_base_call) or m_bDoubleClicked + if(message_words.size () > 4 // enough fields for a normal message + && (message_words.at(2).contains(m_baseCall) || "DE" == message_words.at(2)) + && (message_words.at(3).contains(qso_partner_base_call) or m_bDoubleClicked 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){ setTxMsg(3); m_QSOProgress=ROGER_REPORT; } 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); m_QSOProgress=ROGER_REPORT; } else { @@ -4981,7 +4983,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie m_QSOProgress=ROGER_REPORT; } } 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 (); if (("RRR" == word_3 || (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 - && message_words.size () > 2 && message_words.at (1).contains (m_baseCall) - && message_words.at (2) == "73") { + && message_words.size () > 3 && message_words.at (2).contains (m_baseCall) + && message_words.at (3) == "73") { // 73 back to compound call holder m_ntx=5; ui->txrb5->setChecked(true); m_QSOProgress = SIGNOFF; } else if (!(m_bAutoReply && (m_QSOProgress > CALLING))) { - if ((message_words.size () > 4 && message_words.at (1).contains (m_baseCall) - && message_words.at (4) == "OOO")) { + if ((message_words.size () > 5 && message_words.at (2).contains (m_baseCall) + && message_words.at (5) == "OOO")) { // EME short code report or MSK144/FT8 contest mode reply, send back Tx3 m_ntx=3; m_QSOProgress = ROGER_REPORT; @@ -5136,7 +5150,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie 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) { // 73 back to compound call holder m_ntx=5;