WSJT-X/decodedtext.cpp
Bill Somerville bda874be89 Many improvements to decode double click and auoto-sequencing behaviour
Double-clicks on 73 messages fixed.  Fixed issue with incorrect decode
being  selected  by  double-click. Refined  auto-sequencing  sign  off
handling, any 73 or rr73 free text  near Rx or Tx frequency taken as a
73 from QSO  partner but if a  standard message then must  be from QSO
partner.

Moved functionality from MainWindow to DecodedText class.

More  efficient  picking of  messages  from  decoded text  windows  by
extracting the text block directly.

Tighten up  use of RR73 and  skipping Tx1, these are  now disabled for
relevant compound calls where they would break the QSO exchange.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@8056 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
2017-09-01 05:11:57 +00:00

217 lines
6.2 KiB
C++

#include "decodedtext.h"
#include <QStringList>
#include <QRegularExpression>
extern "C" {
bool stdmsg_(const char* msg, int len);
}
namespace
{
QRegularExpression words_re {R"(^(?:(?<word1>(?:CQ|DE|QRZ)(?:\s?DX|\s(?:[A-Z]{2}|\d{3}))|[A-Z0-9/]+)\s)(?:(?<word2>[A-Z0-9/]+)(?:\sR\s)?(?:\s(?<word3>[-+A-Z0-9]+)(?:\s(?<word4>OOO))?)?)?)"};
}
DecodedText::DecodedText (QString const& the_string)
: string_ {the_string}
, padding_ {the_string.indexOf (" ") > 4 ? 2 : 0} // allow for
// seconds
, message_ {string_.mid (column_qsoText + padding_).trimmed ()}
, is_standard_ {false}
{
string_ = string_.left (column_qsoText + padding_ + 25);
if (message_.length() >= 1)
{
message_ = message_.left (21).remove (QRegularExpression {"[<>]"});
int i1 = message_.indexOf ('\r');
if (i1 > 0)
{
message_ = message_.left (i1 - 1);
}
if (message_.contains (QRegularExpression {"^(CQ|QRZ)\\s"}))
{
// TODO this magic position 16 is guaranteed to be after the
// last space in a decoded CQ or QRZ message but before any
// appended DXCC entity name or worked before information
auto eom_pos = message_.indexOf (' ', 16);
// we always want at least the characters to position 16
if (eom_pos < 16) eom_pos = message_.size () - 1;
// remove DXCC entity and worked B4 status. TODO need a better way to do this
message_ = message_.left (eom_pos + 1);
}
// stdmsg is a fortran routine that packs the text, unpacks it and compares the result
is_standard_ = stdmsg_ ((message_ + " ").toLatin1 ().constData (),22);
}
};
QStringList DecodedText::messageWords () const
{
if (is_standard_)
{
// extract up to the first four message words
return words_re.match (message_).capturedTexts ();
}
return message_.split (' '); // simple word split for free text messages
}
QString DecodedText::CQersCall() const
{
QRegularExpression callsign_re {R"(^(CQ|DE|QRZ)(\s?DX|\s([A-Z]{2}|\d{3}))?\s(?<callsign>[A-Z0-9/]{2,})(\s[A-R]{2}[0-9]{2})?)"};
return callsign_re.match (message_).captured ("callsign");
}
bool DecodedText::isJT65() const
{
return string_.indexOf("#") == column_mode + padding_;
}
bool DecodedText::isJT9() const
{
return string_.indexOf("@") == column_mode + padding_;
}
bool DecodedText::isTX() const
{
int i = string_.indexOf("Tx");
return (i >= 0 && i < 15); // TODO guessing those numbers. Does Tx ever move?
}
bool DecodedText::isLowConfidence () const
{
return QChar {'?'} == string_.mid (padding_ + column_qsoText + 21, 1);
}
int DecodedText::frequencyOffset() const
{
return string_.mid(column_freq + padding_,4).toInt();
}
int DecodedText::snr() const
{
int i1=string_.indexOf(" ")+1;
return string_.mid(i1,3).toInt();
}
float DecodedText::dt() const
{
return string_.mid(column_dt + padding_,5).toFloat();
}
/*
2343 -11 0.8 1259 # YV6BFE F6GUU R-08
2343 -19 0.3 718 # VE6WQ SQ2NIJ -14
2343 -7 0.3 815 # KK4DSD W7VP -16
2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02
0605 Tx 1259 # CQ VK3ACF QF22
*/
// find and extract any report. Returns true if this is a standard message
bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report) const
{
if (message_.size () < 1) return false;
QStringList const& w = message_.split(" ",QString::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 + "/")))))
{
QString tt="";
if(w.size() > 2) tt=w[2];
bool ok;
auto i1=tt.toInt(&ok);
if (ok and i1>=-50 and i1<50)
{
report = tt;
}
else
{
if (tt.mid(0,1)=="R")
{
i1=tt.mid(1).toInt(&ok);
if(ok and i1>=-50 and i1<50)
{
report = tt.mid(1);
}
}
}
}
return is_standard_;
}
// get the first text word, usually the call
QString DecodedText::call() const
{
return words_re.match (message_).captured ("word1");
}
// get the second word, most likely the de call and the third word, most likely grid
void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid) const
{
auto const& match = words_re.match (message_);
call = match.captured ("word2");
grid = match.captured ("word3");
// auto msg = string_;
// if(msg.mid(4,1)!=" ") msg=msg.mid(0,4)+msg.mid(6,-1); //Remove seconds from UTC
// msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
// int i1 = msg.indexOf (" ");
// call = msg.mid (i1 + 1);
// int i2 = call.indexOf (" ");
// if (" R " == call.mid (i2, 3)) // MSK144 contest mode report
// {
// grid = call.mid (i2 + 3, 4);
// }
// else
// {
// grid = call.mid (i2 + 1, 4);
// }
// call = call.left (i2).replace (">", "");
}
unsigned DecodedText::timeInSeconds() const
{
return 3600 * string_.mid (column_time, 2).toUInt ()
+ 60 * string_.mid (column_time + 2, 2).toUInt()
+ (padding_ ? string_.mid (column_time + 2 + padding_, 2).toUInt () : 0U);
}
/*
2343 -11 0.8 1259 # YV6BFE F6GUU R-08
2343 -19 0.3 718 # VE6WQ SQ2NIJ -14
2343 -7 0.3 815 # KK4DSD W7VP -16
2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02
0605 Tx 1259 # CQ VK3ACF QF22
*/
QString DecodedText::report() const // returns a string of the SNR field with a leading + or - followed by two digits
{
int sr = snr();
if (sr<-50)
sr = -50;
else
if (sr > 49)
sr = 49;
QString rpt;
rpt.sprintf("%d",abs(sr));
if (sr > 9)
rpt = "+" + rpt;
else
if (sr >= 0)
rpt = "+0" + rpt;
else
if (sr >= -9)
rpt = "-0" + rpt;
else
rpt = "-" + rpt;
return rpt;
}