mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-08-25 08:52:30 -04:00
Merged from trunk:
------------------------------------------------------------------------ r8016 | k9an | 2017-08-09 16:22:54 +0100 (Wed, 09 Aug 2017) | 1 line Remove call to jtmsg. ------------------------------------------------------------------------ r8017 | k9an | 2017-08-09 16:52:52 +0100 (Wed, 09 Aug 2017) | 1 line Bring a simulation tool up to date. ------------------------------------------------------------------------ r8022 | k9an | 2017-08-13 02:35:13 +0100 (Sun, 13 Aug 2017) | 1 line Improve efficiency of OSD by a factor of 5 to 10 for norder=2 and 3. Use norder=2 for wideband multi-decoding, norder=3 near nfqso and nftx. ------------------------------------------------------------------------ r8026 | k9an | 2017-08-14 16:00:48 +0100 (Mon, 14 Aug 2017) | 1 line Make default MSK144 amplitude polynomial flat. ------------------------------------------------------------------------ r8029 | k1jt | 2017-08-19 14:07:27 +0100 (Sat, 19 Aug 2017) | 1 line Edit the advice displayed by F5. ------------------------------------------------------------------------ r8030 | k1jt | 2017-08-19 23:34:26 +0100 (Sat, 19 Aug 2017) | 1 line Fix a typo. ------------------------------------------------------------------------ r8031 | k9an | 2017-08-22 01:14:51 +0100 (Tue, 22 Aug 2017) | 1 line 1. Improvements to the OSD to allow deeper wideband decoding. 2. Add a third decoding pass. 3. Change symbol metric from max-log to max-amplitude. ------------------------------------------------------------------------ r8032 | k9an | 2017-08-22 01:17:23 +0100 (Tue, 22 Aug 2017) | 1 line Delete unused array. ------------------------------------------------------------------------ r8033 | k9an | 2017-08-22 01:21:59 +0100 (Tue, 22 Aug 2017) | 1 line More cleanup. ------------------------------------------------------------------------ r8034 | k1jt | 2017-08-24 14:38:47 +0100 (Thu, 24 Aug 2017) | 1 line Possible pseudo-code for DXpedition auto-sequencing. ------------------------------------------------------------------------ r8035 | k1jt | 2017-08-25 17:59:58 +0100 (Fri, 25 Aug 2017) | 4 lines Use the most recently edited "CQ xx: message in Tx6 as a template for subsequent regenerations. This means that "CQ DX", "CQ VT", etc., will be presistent until changed back. ------------------------------------------------------------------------ r8036 | k1jt | 2017-08-26 17:30:47 +0100 (Sat, 26 Aug 2017) | 1 line Use a baseline-fitting procedure to improve S/N estimates for FT8. ------------------------------------------------------------------------ r8037 | k1jt | 2017-08-27 13:26:37 +0100 (Sun, 27 Aug 2017) | 1 line Fix the 'Start=0 ==> S/N = -24 dB' problem. ------------------------------------------------------------------------ r8038 | k1jt | 2017-08-27 14:11:56 +0100 (Sun, 27 Aug 2017) | 1 line Change magic 36 back to 37; does this break something else? ------------------------------------------------------------------------ r8039 | k1jt | 2017-08-28 15:32:14 +0100 (Mon, 28 Aug 2017) | 2 lines Correct the behavior of FT8 in "NA VHF Contest mode". ------------------------------------------------------------------------ r8040 | k9an | 2017-08-28 22:09:44 +0100 (Mon, 28 Aug 2017) | 1 line Fix a potential array bounds issue in osd174.f90. ------------------------------------------------------------------------ r8043 | bsomervi | 2017-08-29 04:20:37 +0100 (Tue, 29 Aug 2017) | 1 line Update AD1C cty.dat database to 14th Aug 2017 big CTY.DAT ------------------------------------------------------------------------ r8044 | bsomervi | 2017-08-29 04:20:51 +0100 (Tue, 29 Aug 2017) | 1 line Basic fix of auto sequencing with free text 73 messages, more to come ------------------------------------------------------------------------ r8045 | bsomervi | 2017-08-29 04:46:32 +0100 (Tue, 29 Aug 2017) | 1 line Ensure that auto Tx is disabled when stop Tx on 73 isn't enabled and DX call is cleared ------------------------------------------------------------------------ r8046 | k1jt | 2017-08-29 15:01:55 +0100 (Tue, 29 Aug 2017) | 2 lines Update text in User Guide related to *NA VHF Contest Mode*. ------------------------------------------------------------------------ r8047 | bsomervi | 2017-08-30 03:27:57 +0100 (Wed, 30 Aug 2017) | 7 lines Fix some signoff issues with auto-sequencing 73 messages from other QSOs on frequency should now be ignored rather than being processed. Also some long overdue refactoring and tidying of non-idiomatic C++ code in the logbook directory. ------------------------------------------------------------------------ r8048 | bsomervi | 2017-08-30 14:20:39 +0100 (Wed, 30 Aug 2017) | 1 line Make 73 and RR73 matching of incoming messages for exact while words ------------------------------------------------------------------------ r8049 | k1jt | 2017-08-30 18:06:49 +0100 (Wed, 30 Aug 2017) | 1 line Updates to User Guide. ------------------------------------------------------------------------ git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx-1.8@8050 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
3c996b01dc
commit
f72a40d5bc
@ -366,6 +366,7 @@ set (wsjt_FSRCS
|
|||||||
lib/averms.f90
|
lib/averms.f90
|
||||||
lib/azdist.f90
|
lib/azdist.f90
|
||||||
lib/badmsg.f90
|
lib/badmsg.f90
|
||||||
|
lib/fsk4hf/baseline.f90
|
||||||
lib/bpdecode40.f90
|
lib/bpdecode40.f90
|
||||||
lib/bpdecode144.f90
|
lib/bpdecode144.f90
|
||||||
lib/fsk4hf/bpdecode120.f90
|
lib/fsk4hf/bpdecode120.f90
|
||||||
|
@ -2342,7 +2342,7 @@ Right click for insert and delete options.</string>
|
|||||||
<string><html><head/><body><p>Exchange 4-character grid locators instead of reports. See User Guide for details.</p></body></html></string>
|
<string><html><head/><body><p>Exchange 4-character grid locators instead of reports. See User Guide for details.</p></body></html></string>
|
||||||
</property>
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>FT8 and MSK144 Contest Mode</string>
|
<string>FT8 and MSK144: NA VHF Contest Mode</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@ -2634,12 +2634,12 @@ soundcard changes</string>
|
|||||||
</connection>
|
</connection>
|
||||||
</connections>
|
</connections>
|
||||||
<buttongroups>
|
<buttongroups>
|
||||||
<buttongroup name="CAT_data_bits_button_group"/>
|
|
||||||
<buttongroup name="split_mode_button_group"/>
|
<buttongroup name="split_mode_button_group"/>
|
||||||
|
<buttongroup name="TX_audio_source_button_group"/>
|
||||||
|
<buttongroup name="CAT_stop_bits_button_group"/>
|
||||||
|
<buttongroup name="TX_mode_button_group"/>
|
||||||
|
<buttongroup name="CAT_data_bits_button_group"/>
|
||||||
<buttongroup name="CAT_handshake_button_group"/>
|
<buttongroup name="CAT_handshake_button_group"/>
|
||||||
<buttongroup name="PTT_method_button_group"/>
|
<buttongroup name="PTT_method_button_group"/>
|
||||||
<buttongroup name="CAT_stop_bits_button_group"/>
|
|
||||||
<buttongroup name="TX_audio_source_button_group"/>
|
|
||||||
<buttongroup name="TX_mode_button_group"/>
|
|
||||||
</buttongroups>
|
</buttongroups>
|
||||||
</ui>
|
</ui>
|
||||||
|
133
decodedtext.cpp
133
decodedtext.cpp
@ -7,48 +7,79 @@ extern "C" {
|
|||||||
bool stdmsg_(const char* msg, int len);
|
bool stdmsg_(const char* msg, int len);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DecodedText::CQersCall()
|
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}
|
||||||
{
|
{
|
||||||
QRegularExpression callsign_re {R"(\s(CQ|DE|QRZ)(\s?DX|\s([A-Z]{2}|\d{3}))?\s(?<callsign>[A-Z0-9/]{2,})(\s[A-R]{2}[0-9]{2})?)"};
|
if (message_.length() >= 1)
|
||||||
return callsign_re.match (_string).captured ("callsign");
|
{
|
||||||
|
message_ = message_.left (22).remove (QRegularExpression {"[<>]"});
|
||||||
|
int i1 = message_.indexOf ('\r');
|
||||||
|
if (i1 > 0)
|
||||||
|
{
|
||||||
|
message_ = message_.left (i1 - 1);
|
||||||
|
}
|
||||||
|
// stdmsg is a fortran routine that packs the text, unpacks it and compares the result
|
||||||
|
is_standard_ = stdmsg_ ((message_ + " ").toLatin1 ().constData (),22);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void DecodedText::removeAddedInfo ()
|
||||||
|
{
|
||||||
|
if (string_.indexOf (" CQ ") > 0) {
|
||||||
|
// TODO this magic 37 characters is also referenced in DisplayText::_appendDXCCWorkedB4()
|
||||||
|
auto eom_pos = string_.indexOf (' ', 37);
|
||||||
|
if (eom_pos < 37) eom_pos = string_.size () - 1; // we always want at least the characters
|
||||||
|
// to position 37
|
||||||
|
string_ = string_.left (eom_pos + 1); // remove DXCC entity and worked B4 status. TODO need a better way to do this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
bool DecodedText::isJT65() const
|
||||||
{
|
{
|
||||||
return _string.indexOf("#") == column_mode + padding_;
|
return string_.indexOf("#") == column_mode + padding_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecodedText::isJT9()
|
bool DecodedText::isJT9() const
|
||||||
{
|
{
|
||||||
return _string.indexOf("@") == column_mode + padding_;
|
return string_.indexOf("@") == column_mode + padding_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecodedText::isTX()
|
bool DecodedText::isTX() const
|
||||||
{
|
{
|
||||||
int i = _string.indexOf("Tx");
|
int i = string_.indexOf("Tx");
|
||||||
return (i >= 0 && i < 15); // TODO guessing those numbers. Does Tx ever move?
|
return (i >= 0 && i < 15); // TODO guessing those numbers. Does Tx ever move?
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecodedText::isLowConfidence ()
|
bool DecodedText::isLowConfidence () const
|
||||||
{
|
{
|
||||||
return QChar {'?'} == _string.mid (padding_ + column_qsoText + 21, 1);
|
return QChar {'?'} == string_.mid (padding_ + column_qsoText + 21, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DecodedText::frequencyOffset()
|
int DecodedText::frequencyOffset() const
|
||||||
{
|
{
|
||||||
return _string.mid(column_freq + padding_,4).toInt();
|
return string_.mid(column_freq + padding_,4).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
int DecodedText::snr()
|
int DecodedText::snr() const
|
||||||
{
|
{
|
||||||
int i1=_string.indexOf(" ")+1;
|
int i1=string_.indexOf(" ")+1;
|
||||||
return _string.mid(i1,3).toInt();
|
return string_.mid(i1,3).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
float DecodedText::dt()
|
float DecodedText::dt() const
|
||||||
{
|
{
|
||||||
return _string.mid(column_dt + padding_,5).toFloat();
|
return string_.mid(column_dt + padding_,5).toFloat();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -61,62 +92,56 @@ float DecodedText::dt()
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// find and extract any report. Returns true if this is a standard message
|
// 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)
|
bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report) const
|
||||||
{
|
{
|
||||||
QString msg=_string.mid(column_qsoText + padding_).trimmed();
|
if (message_.size () < 1) return false;
|
||||||
if(msg.length() < 1) return false;
|
|
||||||
msg = msg.left (22).remove (QRegularExpression {"[<>]"});
|
|
||||||
int i1=msg.indexOf('\r');
|
|
||||||
if (i1>0)
|
|
||||||
msg=msg.left (i1-1);
|
|
||||||
bool b = stdmsg_ ((msg + " ").toLatin1().constData(),22); // stdmsg is a fortran routine that packs the text, unpacks it and compares the result
|
|
||||||
|
|
||||||
QStringList w=msg.split(" ",QString::SkipEmptyParts);
|
QStringList const& w = message_.split(" ",QString::SkipEmptyParts);
|
||||||
if(w.size ()
|
if (w.size ()
|
||||||
&& b && (w[0] == myBaseCall
|
&& is_standard_ && (w[0] == myBaseCall
|
||||||
|| w[0].endsWith ("/" + myBaseCall)
|
|| w[0].endsWith ("/" + myBaseCall)
|
||||||
|| w[0].startsWith (myBaseCall + "/")
|
|| w[0].startsWith (myBaseCall + "/")
|
||||||
|| (w.size () > 1 && !dxBaseCall.isEmpty ()
|
|| (w.size () > 1 && !dxBaseCall.isEmpty ()
|
||||||
&& (w[1] == dxBaseCall
|
&& (w[1] == dxBaseCall
|
||||||
|| w[1].endsWith ("/" + dxBaseCall)
|
|| w[1].endsWith ("/" + dxBaseCall)
|
||||||
|| w[1].startsWith (dxBaseCall + "/")))))
|
|| w[1].startsWith (dxBaseCall + "/")))))
|
||||||
{
|
{
|
||||||
QString tt="";
|
QString tt="";
|
||||||
if(w.size() > 2) tt=w[2];
|
if(w.size() > 2) tt=w[2];
|
||||||
bool ok;
|
bool ok;
|
||||||
i1=tt.toInt(&ok);
|
auto i1=tt.toInt(&ok);
|
||||||
if (ok and i1>=-50 and i1<50)
|
if (ok and i1>=-50 and i1<50)
|
||||||
{
|
{
|
||||||
report = tt;
|
report = tt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tt.mid(0,1)=="R")
|
if (tt.mid(0,1)=="R")
|
||||||
{
|
{
|
||||||
i1=tt.mid(1).toInt(&ok);
|
i1=tt.mid(1).toInt(&ok);
|
||||||
if(ok and i1>=-50 and i1<50)
|
if(ok and i1>=-50 and i1<50)
|
||||||
{
|
{
|
||||||
report = tt.mid(1);
|
report = tt.mid(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b;
|
return is_standard_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the first text word, usually the call
|
// get the first text word, usually the call
|
||||||
QString DecodedText::call()
|
QString DecodedText::call() const
|
||||||
{
|
{
|
||||||
auto call = _string;
|
auto call = string_;
|
||||||
call = call.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
|
call = call.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
|
||||||
int i = call.indexOf(" ");
|
int i = call.indexOf(" ");
|
||||||
return call.mid(0,i);
|
return call.mid(0,i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid)
|
void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid) const
|
||||||
{
|
{
|
||||||
auto msg = _string;
|
auto msg = string_;
|
||||||
if(msg.mid(4,1)!=" ") msg=msg.mid(0,4)+msg.mid(6,-1); //Remove seconds from UTC
|
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_);
|
msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
|
||||||
int i1 = msg.indexOf (" ");
|
int i1 = msg.indexOf (" ");
|
||||||
@ -133,9 +158,9 @@ void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid)
|
|||||||
call = call.left (i2).replace (">", "");
|
call = call.left (i2).replace (">", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
int DecodedText::timeInSeconds()
|
int DecodedText::timeInSeconds() const
|
||||||
{
|
{
|
||||||
return 60*_string.mid(column_time,2).toInt() + _string.mid(2,2).toInt();
|
return 60*string_.mid(column_time,2).toInt() + string_.mid(2,2).toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -147,7 +172,7 @@ int DecodedText::timeInSeconds()
|
|||||||
0605 Tx 1259 # CQ VK3ACF QF22
|
0605 Tx 1259 # CQ VK3ACF QF22
|
||||||
*/
|
*/
|
||||||
|
|
||||||
QString DecodedText::report() // returns a string of the SNR field with a leading + or - followed by two digits
|
QString DecodedText::report() const // returns a string of the SNR field with a leading + or - followed by two digits
|
||||||
{
|
{
|
||||||
int sr = snr();
|
int sr = snr();
|
||||||
if (sr<-50)
|
if (sr<-50)
|
||||||
|
@ -27,54 +27,41 @@
|
|||||||
class DecodedText
|
class DecodedText
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void operator=(const QString &rhs)
|
explicit DecodedText (QString const&);
|
||||||
{
|
|
||||||
_string = rhs;
|
|
||||||
padding_ = _string.indexOf (" ") > 4 ? 2 : 0; // allow for seconds
|
|
||||||
};
|
|
||||||
void operator=(const QByteArray &rhs)
|
|
||||||
{
|
|
||||||
_string = rhs;
|
|
||||||
padding_ = _string.indexOf (" ") > 4 ? 2 : 0; // allow for seconds
|
|
||||||
};
|
|
||||||
|
|
||||||
void operator+=(const QString &rhs)
|
QString string() const { return string_; };
|
||||||
{
|
void removeAddedInfo ();
|
||||||
_string += rhs;
|
int indexOf(QString s) const { return string_.indexOf(s); };
|
||||||
};
|
int indexOf(QString s, int i) const { return string_.indexOf(s,i); };
|
||||||
|
QString mid(int f, int t) const { return string_.mid(f,t); };
|
||||||
|
QString left(int i) const { return string_.left(i); };
|
||||||
|
|
||||||
QString string() { return _string; };
|
void clear() { string_.clear(); };
|
||||||
|
|
||||||
int indexOf(QString s) { return _string.indexOf(s); };
|
QString CQersCall() const;
|
||||||
int indexOf(QString s, int i) { return _string.indexOf(s,i); };
|
|
||||||
QString mid(int f, int t) { return _string.mid(f,t); };
|
|
||||||
QString left(int i) { return _string.left(i); };
|
|
||||||
|
|
||||||
void clear() { _string.clear(); };
|
bool isJT65() const;
|
||||||
|
bool isJT9() const;
|
||||||
QString CQersCall();
|
bool isTX() const;
|
||||||
|
bool isStandardMessage () const {return is_standard_;}
|
||||||
bool isJT65();
|
bool isLowConfidence () const;
|
||||||
bool isJT9();
|
int frequencyOffset() const; // hertz offset from the tuned dial or rx frequency, aka audio frequency
|
||||||
bool isTX();
|
int snr() const;
|
||||||
bool isLowConfidence ();
|
float dt() const;
|
||||||
int frequencyOffset(); // hertz offset from the tuned dial or rx frequency, aka audio frequency
|
|
||||||
int snr();
|
|
||||||
float dt();
|
|
||||||
|
|
||||||
// find and extract any report. Returns true if this is a standard message
|
// find and extract any report. Returns true if this is a standard message
|
||||||
bool report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report);
|
bool report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report) const;
|
||||||
|
|
||||||
// get the first message text word, usually the call
|
// get the first message text word, usually the call
|
||||||
QString call();
|
QString call() const;
|
||||||
|
|
||||||
// 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
|
||||||
void deCallAndGrid(/*out*/QString& call, QString& grid);
|
void deCallAndGrid(/*out*/QString& call, QString& grid) const;
|
||||||
|
|
||||||
int timeInSeconds();
|
int timeInSeconds() const;
|
||||||
|
|
||||||
// returns a string of the SNR field with a leading + or - followed by two digits
|
// returns a string of the SNR field with a leading + or - followed by two digits
|
||||||
QString report();
|
QString report() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// These define the columns in the decoded text where fields are to be found.
|
// These define the columns in the decoded text where fields are to be found.
|
||||||
@ -86,8 +73,10 @@ private:
|
|||||||
column_mode = 19,
|
column_mode = 19,
|
||||||
column_qsoText = 22 };
|
column_qsoText = 22 };
|
||||||
|
|
||||||
QString _string;
|
QString string_;
|
||||||
int padding_;
|
int padding_;
|
||||||
|
QString message_;
|
||||||
|
bool is_standard_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DECODEDTEXT_H
|
#endif // DECODEDTEXT_H
|
||||||
|
@ -81,7 +81,7 @@ void DisplayText::appendText(QString const& text, QColor bg)
|
|||||||
|
|
||||||
|
|
||||||
QString DisplayText::appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg,
|
QString DisplayText::appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg,
|
||||||
LogBook logBook, QColor color_CQ,
|
LogBook const& logBook, QColor color_CQ,
|
||||||
QColor color_DXCC,
|
QColor color_DXCC,
|
||||||
QColor color_NewCall)
|
QColor color_NewCall)
|
||||||
{
|
{
|
||||||
@ -158,8 +158,8 @@ QString DisplayText::appendDXCCWorkedB4(QString message, QString const& callsign
|
|||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisplayText::displayDecodedText(DecodedText decodedText, QString myCall,
|
void DisplayText::displayDecodedText(DecodedText const& decodedText, QString const& myCall,
|
||||||
bool displayDXCCEntity, LogBook logBook,
|
bool displayDXCCEntity, LogBook const& logBook,
|
||||||
QColor color_CQ, QColor color_MyCall,
|
QColor color_CQ, QColor color_MyCall,
|
||||||
QColor color_DXCC, QColor color_NewCall)
|
QColor color_DXCC, QColor color_NewCall)
|
||||||
{
|
{
|
||||||
|
@ -17,8 +17,8 @@ public:
|
|||||||
|
|
||||||
void setContentFont (QFont const&);
|
void setContentFont (QFont const&);
|
||||||
void insertLineSpacer(QString const&);
|
void insertLineSpacer(QString const&);
|
||||||
void displayDecodedText(DecodedText decodedText, QString myCall, bool displayDXCCEntity,
|
void displayDecodedText(DecodedText const& decodedText, QString const& myCall, bool displayDXCCEntity,
|
||||||
LogBook logBook, QColor color_CQ, QColor color_MyCall,
|
LogBook const& logBook, QColor color_CQ, QColor color_MyCall,
|
||||||
QColor color_DXCC, QColor color_NewCall);
|
QColor color_DXCC, QColor color_NewCall);
|
||||||
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
||||||
QColor color_TxMsg, bool bFastMode);
|
QColor color_TxMsg, bool bFastMode);
|
||||||
@ -32,7 +32,7 @@ protected:
|
|||||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg, LogBook logBook,
|
QString appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg, LogBook const& logBook,
|
||||||
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
|
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
|
||||||
|
|
||||||
QFont char_font_;
|
QFont char_font_;
|
||||||
|
@ -9,33 +9,25 @@ When an operator decides to answer a CQ, he already knows his own
|
|||||||
callsign and that of his potential QSO partner. He therefore knows
|
callsign and that of his potential QSO partner. He therefore knows
|
||||||
what to expect for at least 56 of the 72 message bits in a
|
what to expect for at least 56 of the 72 message bits in a
|
||||||
standard-format response to his call. The _WSJT-X_ decoders for QRA64
|
standard-format response to his call. The _WSJT-X_ decoders for QRA64
|
||||||
and FT8 can use these AP bits to decode messages containing them with
|
and FT8 can use these and similar AP bits to decode messages
|
||||||
higher sensitivity than otherwise possible.
|
containing them with higher sensitivity than otherwise possible.
|
||||||
|
|
||||||
We have implemented AP decoding in slightly different ways in QRA64
|
We have implemented AP decoding in slightly different ways in QRA64
|
||||||
and FT8. To provide some explicit examples for users, we provide here
|
and FT8. To provide some explicit examples for users, we provide here
|
||||||
a brief description of the FT8 behavior.
|
a brief description of the FT8 behavior.
|
||||||
|
|
||||||
The FT8 decoder always tries first to decode a signal without using
|
|
||||||
any AP information. If this attempt fails, and if *Enable AP* is
|
|
||||||
checked on the *Decode* menu, a second attempt hypothesizes that the
|
|
||||||
message contains callsigns MyCall and DxCall. If the QSO has
|
|
||||||
progressed to the point where signal reports have been exchanged, a
|
|
||||||
third attempt hypothesizes that the message contains the known
|
|
||||||
callsigns followed by RRR, RR73, or 73.
|
|
||||||
|
|
||||||
AP decoding attempts effectively set the AP bits to the hypothesized
|
AP decoding attempts effectively set the AP bits to the hypothesized
|
||||||
values, as if they had been received perfectly. The decoder then
|
values, as if they had been received correctly. The decoder then
|
||||||
proceeds to determine whether the remaining message and parity bits
|
proceeds to determine whether the remaining message and parity bits
|
||||||
are consistent with the hypothesized AP bits. If a codeword is found
|
are consistent with the hypothesized AP bits. If a codeword is found
|
||||||
that the decoder judges to have high (but not overwhelmingly high)
|
that the decoder judges to have high (but not overwhelmingly high)
|
||||||
probability of being correct, a ? character is appended when the
|
probability of being correct, a ? character is appended when the
|
||||||
decoded message is displayed. Decodes thus marked are not sent to
|
decoded message is displayed. To avoid misleading spots of occasional
|
||||||
{pskreporter} to avoid occasional misleading spots of false decodes.
|
false decodes, messages so marked are not forwarded to {pskreporter}.
|
||||||
|
|
||||||
Successful AP decodes are always labeled with an end-of-line indicator
|
Successful AP decodes are always labeled with an end-of-line indicator
|
||||||
of the form aP, where P is one of the single-digit AP decoding types
|
of the form aP, where P is one of the single-digit AP decoding types
|
||||||
listed in Table 1. For example, an a2 designator says that the
|
listed in Table 1. For example, an `a2` designator says that the
|
||||||
successful decode used MyCall as hypothetically known information.
|
successful decode used MyCall as hypothetically known information.
|
||||||
|
|
||||||
[[AP_INFO_TABLE]]
|
[[AP_INFO_TABLE]]
|
||||||
@ -51,6 +43,23 @@ successful decode used MyCall as hypothetically known information.
|
|||||||
|6 | MyCall DxCall RR73
|
|6 | MyCall DxCall RR73
|
||||||
|===============================================
|
|===============================================
|
||||||
|
|
||||||
|
Table 2 lists the six possible QSO states that are tracked by the
|
||||||
|
WSJT-X auto-sequencer, along with the type of AP decoding that would
|
||||||
|
be attempted in each state.
|
||||||
|
|
||||||
|
[[AP decoding types for each QSO state]]
|
||||||
|
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|
||||||
|
|===========================================
|
||||||
|
|State |AP type
|
||||||
|
|CALLING | 1, 2
|
||||||
|
|REPLYING | 2, 3
|
||||||
|
|REPORT | 2, 3
|
||||||
|
|ROGER_REPORT | 3, 4, 5, 6
|
||||||
|
|ROGERS | 3, 4, 5, 6
|
||||||
|
|SIGNOFF | 3, 1, 2
|
||||||
|
|===========================================
|
||||||
|
|
||||||
|
|
||||||
=== Decoded Lines
|
=== Decoded Lines
|
||||||
|
|
||||||
Displayed information accompanying decoded messages generally includes UTC,
|
Displayed information accompanying decoded messages generally includes UTC,
|
||||||
|
@ -29,7 +29,7 @@ in other parts of the world.
|
|||||||
|
|
||||||
- During the calibration procedure, the radio's USB dial frequency is
|
- During the calibration procedure, the radio's USB dial frequency is
|
||||||
offset 1500 Hz below each *FreqCal* entry in the default frequencies
|
offset 1500 Hz below each *FreqCal* entry in the default frequencies
|
||||||
list. As shown in the ecreen shot below, detected signal carriers
|
list. As shown in the screen shot below, detected signal carriers
|
||||||
therefore appear at about 1500 Hz in the WSJT-X waterfall.
|
therefore appear at about 1500 Hz in the WSJT-X waterfall.
|
||||||
|
|
||||||
image::FreqCal.png[align="left",alt="FreqCal"]
|
image::FreqCal.png[align="left",alt="FreqCal"]
|
||||||
|
@ -40,11 +40,22 @@ additional information is sent in place of the grid locator or by
|
|||||||
encoding additional information into some of the 6 million available
|
encoding additional information into some of the 6 million available
|
||||||
slots mentioned above.
|
slots mentioned above.
|
||||||
|
|
||||||
Finally, the message compression algorithm supports messages starting
|
As a convenience for sending directed CQ messages, the compression
|
||||||
with `CQ AA` through `CQ ZZ`. Such messages are encoded by
|
algorithm supports messages starting with `CQ AA` through `CQ ZZ`.
|
||||||
sending `E9AA` through `E9ZZ` in place of the first callsign of a
|
These message fragments are encoded internally as if they were the
|
||||||
standard message. Upon reception these calls are converted back to
|
callsigns `E9AA` through `E9ZZ`. Upon reception they are converted
|
||||||
the form `CQ AA` through `CQ ZZ`.
|
back to the form `CQ AA` through `CQ ZZ`, for display to the user.
|
||||||
|
|
||||||
|
The FT8 and MSK144 modes support a special feature allowing convenient
|
||||||
|
transmission and acknowledgment of four-character grid locators, the
|
||||||
|
required exchanges in most North American VHF contests. With this
|
||||||
|
Contest Mode enabled, _WSJT-X_ supports messages of the form `W9XYZ
|
||||||
|
K1ABC R FN42` by converting the grid locator to that of its
|
||||||
|
diametrically opposite point on Earth. The receiving program
|
||||||
|
recognizes a locator implying a distance greater than 10,000 km, does
|
||||||
|
the reverse transformation, and inserts the implied "`R`". Obviously,
|
||||||
|
this mode should not be used on the HF bands or under other
|
||||||
|
circumstances where world-wide propagation is possible.
|
||||||
|
|
||||||
To be useful on channels with low signal-to-noise ratio, this kind of
|
To be useful on channels with low signal-to-noise ratio, this kind of
|
||||||
lossless message compression requires use of a strong forward error
|
lossless message compression requires use of a strong forward error
|
||||||
@ -289,15 +300,6 @@ with constant envelope, equivalent to a Minimum Shift Keying (MSK)
|
|||||||
waveform. Frame duration is 72 ms, so the effective character
|
waveform. Frame duration is 72 ms, so the effective character
|
||||||
transmission rate for standard messages is up to 250 cps.
|
transmission rate for standard messages is up to 250 cps.
|
||||||
|
|
||||||
Contest Mode in MSK144 conveys an additional acknowledgment bit (the
|
|
||||||
"`R`" in a message of the form `W9XYZ K1ABC R FN42`) by using the fact
|
|
||||||
that meteor scatter and other propagation modes usable with MSK144 are
|
|
||||||
generally effective only out to distances of order 2500 km. To convey
|
|
||||||
the message fragment `R FN42`, WSJT-X encodes the locator as that of
|
|
||||||
its antipodes. The receiving program recognizes a locator with
|
|
||||||
distance greater than 10,000 km, does the reverse transformation, and
|
|
||||||
inserts the implied "`R`".
|
|
||||||
|
|
||||||
MSK144 also supports short-form messages that can be used after QSO
|
MSK144 also supports short-form messages that can be used after QSO
|
||||||
partners have exchanged both callsigns. Short messages consist of 4
|
partners have exchanged both callsigns. Short messages consist of 4
|
||||||
bits encoding R+report, RRR, or 73, together with a 12-bit hash code
|
bits encoding R+report, RRR, or 73, together with a 12-bit hash code
|
||||||
|
@ -31,9 +31,10 @@ IMPORTANT: For the health of your T/R relays and external
|
|||||||
preamplifier, we strongly recommend using a hardware sequencer and
|
preamplifier, we strongly recommend using a hardware sequencer and
|
||||||
testing to make sure that sequencing is correct.
|
testing to make sure that sequencing is correct.
|
||||||
|
|
||||||
- Check *FT8 and MSK144 Contest Mode* to enable generation and
|
- Check *FT8 and MSK144: NA VHF Contest Mode* to enable generation and
|
||||||
auto-sequencing of MSK144 messages with four-character grid locators
|
auto-sequencing of messages using four-character grid locators in
|
||||||
in place of signal reports.
|
place of signal reports, as required for most North American VHF
|
||||||
|
contests.
|
||||||
|
|
||||||
- Check *x 2 Tone spacing* to generate Tx audio with twice the normal
|
- Check *x 2 Tone spacing* to generate Tx audio with twice the normal
|
||||||
tone spacing. This feature is intended for use with specialized LF/MF
|
tone spacing. This feature is intended for use with specialized LF/MF
|
||||||
|
@ -279,11 +279,11 @@ messages at 50 or 70 MHz. At these frequencies, most pings are long
|
|||||||
enough to support standard messages -- which have the advantage of
|
enough to support standard messages -- which have the advantage of
|
||||||
being readable by anyone listening in.
|
being readable by anyone listening in.
|
||||||
|
|
||||||
- A special *Contest Mode* for MSK144 can be activated by checking a
|
- A special *VHF Contest Mode* for FT8 and MSK144 can be activated by
|
||||||
box on the *Settings | Advanced* tab. This mode is configured
|
checking a box on the *Settings | Advanced* tab. This mode is
|
||||||
especially for VHF contests in which four-character grid locators are
|
configured especially for VHF contests in which four-character grid
|
||||||
the required exchange. When *Contest Mode* is active, the standard QSO
|
locators are the required exchange. When *Contest Mode* is active,
|
||||||
sequence looks like this:
|
the standard QSO sequence looks like this:
|
||||||
|
|
||||||
CQ K1ABC FN42
|
CQ K1ABC FN42
|
||||||
K1ABC W9XYZ EN37
|
K1ABC W9XYZ EN37
|
||||||
|
71
lib/DXped_pseudo_code.txt
Normal file
71
lib/DXped_pseudo_code.txt
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
Auto-Sequencing algorithm for DXpedition station:
|
||||||
|
|
||||||
|
Start:
|
||||||
|
CQMsg = "CQ VK9MA" (or "CQ UP VK9MA", "CQ 116 VK9MA", etc.)
|
||||||
|
TxMsg = CQMsg
|
||||||
|
Ntry = 0
|
||||||
|
QCALL = "" # Callsign of current QSO partner
|
||||||
|
go to Transmit
|
||||||
|
|
||||||
|
Transmit:
|
||||||
|
TX # (... takes 13.6 s)
|
||||||
|
go to Receive
|
||||||
|
|
||||||
|
Receive:
|
||||||
|
RX # (... takes ~14 s)
|
||||||
|
N = number of decodes # RxMsg[i], i=1,N
|
||||||
|
if(N == 0)
|
||||||
|
go to Transmit
|
||||||
|
J = index of a reply from current QCALL # RxMsg[J] = "VK9MA QCALL R<rpt>"
|
||||||
|
|
||||||
|
if(QCALL == "") # No QSO in progress
|
||||||
|
Select new QCALL # Op chooses a caller
|
||||||
|
if(QCALL == "")
|
||||||
|
TxMsg = CQMsg # No callers, we'll CQ again
|
||||||
|
else # QSO in progress
|
||||||
|
if(J >= 1) # Expected message was received
|
||||||
|
log the QSO with QCALL
|
||||||
|
QCALL = ""
|
||||||
|
Select new QCALL # Op chooses a new caller
|
||||||
|
if(QCALL != "")
|
||||||
|
TxMsg = "73 NOW QCALL <rpt>" # Start a new QSO
|
||||||
|
else
|
||||||
|
TxMsg = "73 " + CQMsg # No callers, we'll CQ again
|
||||||
|
else
|
||||||
|
Ntry = Ntry + 1 # Expected msg not received
|
||||||
|
if(Ntry <= NtryMax)
|
||||||
|
go to Transmit # Ask for a repeat
|
||||||
|
else
|
||||||
|
QCALL = "" # Max tries exceeded, abort this QSO
|
||||||
|
Select new QCALL # Choose a new caller
|
||||||
|
if(QCALL != "")
|
||||||
|
TxMsg = "NIL NOW QCALL <rpt>" # Start a new QSO
|
||||||
|
else
|
||||||
|
TxMsg = "NIL " + CQMSG # No callers, we'll CQ again
|
||||||
|
go to Transmit
|
||||||
|
|
||||||
|
|
||||||
|
Auto-Sequencing algorithm for those calling the DXpedition:
|
||||||
|
|
||||||
|
Start:
|
||||||
|
TxMsg = "VK9MA MyCall"
|
||||||
|
InQSO = false
|
||||||
|
|
||||||
|
Transmit:
|
||||||
|
TX # (... takes 13.6 s)
|
||||||
|
go to Receive
|
||||||
|
|
||||||
|
Receive:
|
||||||
|
RX # (... takes ~14 s)
|
||||||
|
if(RxMsg[i] contains "MyCall <rpt>")
|
||||||
|
InQSO = true
|
||||||
|
TxMsg = "VK9MA MyCall R<rpt>"
|
||||||
|
go to Transmit
|
||||||
|
|
||||||
|
if(RxMsg[i] contains "<rpt>")
|
||||||
|
TxEnable = false
|
||||||
|
go to Receive
|
||||||
|
|
||||||
|
if(RxMsg[i] contains "CQ VK9MA")
|
||||||
|
TxEnable = true
|
||||||
|
go to Transmit
|
@ -16,8 +16,10 @@ subroutine analytic(d,npts,nfft,c,pc,beq)
|
|||||||
logical*1 beq ! boolean static equalizer flag
|
logical*1 beq ! boolean static equalizer flag
|
||||||
|
|
||||||
data nfft0/0/
|
data nfft0/0/
|
||||||
data aclast/1.0,0.0,0.0,0.0,0.0/
|
data aclast/0.0,0.0,0.0,0.0,0.0/
|
||||||
data ac/1.0,0.05532,0.11438,0.12918,0.09274/ ! amp coeffs for TS2000
|
data pclast/0.0,0.0,0.0,0.0,0.0/
|
||||||
|
! data ac/1.0,0.05532,0.11438,0.12918,0.09274/ ! amp coeffs for TS2000
|
||||||
|
data ac/1.0,0.0,0.0,0.0,0.0/
|
||||||
|
|
||||||
save corr,nfft0,h,ac,aclast,pclast,pi,t,beta
|
save corr,nfft0,h,ac,aclast,pclast,pi,t,beta
|
||||||
|
|
||||||
@ -43,8 +45,8 @@ subroutine analytic(d,npts,nfft,c,pc,beq)
|
|||||||
if( any(aclast .ne. ac) .or. any(pclast .ne. pc) ) then
|
if( any(aclast .ne. ac) .or. any(pclast .ne. pc) ) then
|
||||||
aclast=ac
|
aclast=ac
|
||||||
pclast=pc
|
pclast=pc
|
||||||
write(*,3001) pc
|
! write(*,3001) pc
|
||||||
3001 format('Phase coeffs:',5f12.6)
|
!3001 format('Phase coeffs:',5f12.6)
|
||||||
do i=1,nh+1
|
do i=1,nh+1
|
||||||
ff=(i-1)*df
|
ff=(i-1)*df
|
||||||
f=ff-1500.0
|
f=ff-1500.0
|
||||||
|
48
lib/fsk4hf/baseline.f90
Normal file
48
lib/fsk4hf/baseline.f90
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
subroutine baseline(s,nfa,nfb,sbase)
|
||||||
|
|
||||||
|
! Fit baseline to spectrum (for FT8)
|
||||||
|
! Input: s(npts) Linear scale in power
|
||||||
|
! Output: sbase(npts) Baseline
|
||||||
|
|
||||||
|
implicit real*8 (a-h,o-z)
|
||||||
|
real*4 s(1920)
|
||||||
|
real*4 sbase(1920)
|
||||||
|
real*4 base
|
||||||
|
real*8 x(1000),y(1000),a(5)
|
||||||
|
data nseg/10/,npct/10/
|
||||||
|
|
||||||
|
df=12000.0/3840.0 !3.125 Hz
|
||||||
|
ia=max(1,nint(nfa/df))
|
||||||
|
ib=nint(nfb/df)
|
||||||
|
do i=ia,ib
|
||||||
|
s(i)=10.0*log10(s(i)) !Convert to dB scale
|
||||||
|
enddo
|
||||||
|
|
||||||
|
nterms=5
|
||||||
|
nlen=(ib-ia+1)/nseg !Length of test segment
|
||||||
|
i0=(ib-ia+1)/2 !Midpoint
|
||||||
|
k=0
|
||||||
|
do n=1,nseg !Loop over all segments
|
||||||
|
ja=ia + (n-1)*nlen
|
||||||
|
jb=ja+nlen-1
|
||||||
|
call pctile(s(ja),nlen,npct,base) !Find lowest npct of points
|
||||||
|
do i=ja,jb
|
||||||
|
if(s(i).le.base) then
|
||||||
|
if (k.lt.1000) k=k+1 !Save all "lower envelope" points
|
||||||
|
x(k)=i-i0
|
||||||
|
y(k)=s(i)
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
kz=k
|
||||||
|
a=0.
|
||||||
|
call polyfit(x,y,y,kz,nterms,0,a,chisqr) !Fit a low-order polynomial
|
||||||
|
do i=ia,ib
|
||||||
|
t=i-i0
|
||||||
|
sbase(i)=a(1)+t*(a(2)+t*(a(3)+t*(a(4)+t*(a(5))))) + 0.65
|
||||||
|
! write(51,3051) i*df,s(i),sbase(i)
|
||||||
|
!3051 format(3f12.3)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine baseline
|
@ -1,6 +1,6 @@
|
|||||||
subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
||||||
lsubtract,nagain,iaptype,mygrid6,bcontest,sync0,f1,xdt,apsym,nharderrors,&
|
lsubtract,nagain,iaptype,mygrid6,bcontest,sync0,f1,xdt,xbase,apsym, &
|
||||||
dmin,nbadcrc,ipass,iera,message,xsnr)
|
nharderrors,dmin,nbadcrc,ipass,iera,message,xsnr)
|
||||||
|
|
||||||
use timer_module, only: timer
|
use timer_module, only: timer
|
||||||
include 'ft8_params.f90'
|
include 'ft8_params.f90'
|
||||||
@ -12,7 +12,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
|||||||
real a(5)
|
real a(5)
|
||||||
real s1(0:7,ND),s2(0:7,NN)
|
real s1(0:7,ND),s2(0:7,NN)
|
||||||
real ps(0:7)
|
real ps(0:7)
|
||||||
real rxdata(3*ND),rxdatap(3*ND)
|
real bmeta(3*ND),bmetap(3*ND)
|
||||||
real llr(3*ND),llra(3*ND),llr0(3*ND),llrap(3*ND) !Soft symbols
|
real llr(3*ND),llra(3*ND),llr0(3*ND),llrap(3*ND) !Soft symbols
|
||||||
real dd0(15*12000)
|
real dd0(15*12000)
|
||||||
integer*1 decoded(KK),apmask(3*ND),cw(3*ND)
|
integer*1 decoded(KK),apmask(3*ND),cw(3*ND)
|
||||||
@ -122,7 +122,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
|||||||
csymb=cmplx(0.0,0.0)
|
csymb=cmplx(0.0,0.0)
|
||||||
if( i1.ge.1 .and. i1+31 .le. NP2 ) csymb=cd0(i1:i1+31)
|
if( i1.ge.1 .and. i1+31 .le. NP2 ) csymb=cd0(i1:i1+31)
|
||||||
call four2a(csymb,32,1,-1,1)
|
call four2a(csymb,32,1,-1,1)
|
||||||
s2(0:7,k)=abs(csymb(1:8))
|
s2(0:7,k)=abs(csymb(1:8))/1e3
|
||||||
enddo
|
enddo
|
||||||
|
|
||||||
! sync quality check
|
! sync quality check
|
||||||
@ -146,39 +146,38 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
|||||||
|
|
||||||
j=0
|
j=0
|
||||||
do k=1,NN
|
do k=1,NN
|
||||||
if(k.le.7) cycle
|
if(k.le.7) cycle
|
||||||
if(k.ge.37 .and. k.le.43) cycle
|
if(k.ge.37 .and. k.le.43) cycle
|
||||||
if(k.gt.72) cycle
|
if(k.gt.72) cycle
|
||||||
j=j+1
|
j=j+1
|
||||||
s1(0:7,j)=s2(0:7,k)
|
s1(0:7,j)=s2(0:7,k)
|
||||||
enddo
|
enddo
|
||||||
|
|
||||||
do j=1,ND
|
do j=1,ND
|
||||||
ps=s1(0:7,j)
|
|
||||||
where (ps.gt.0.0) ps=log(ps)
|
|
||||||
r1=max(ps(1),ps(3),ps(5),ps(7))-max(ps(0),ps(2),ps(4),ps(6))
|
|
||||||
r2=max(ps(2),ps(3),ps(6),ps(7))-max(ps(0),ps(1),ps(4),ps(5))
|
|
||||||
r4=max(ps(4),ps(5),ps(6),ps(7))-max(ps(0),ps(1),ps(2),ps(3))
|
|
||||||
i4=3*j-2
|
i4=3*j-2
|
||||||
i2=3*j-1
|
i2=3*j-1
|
||||||
i1=3*j
|
i1=3*j
|
||||||
rxdata(i4)=r4
|
ps=s1(0:7,j)
|
||||||
rxdata(i2)=r2
|
r1=max(ps(1),ps(3),ps(5),ps(7))-max(ps(0),ps(2),ps(4),ps(6))
|
||||||
rxdata(i1)=r1
|
r2=max(ps(2),ps(3),ps(6),ps(7))-max(ps(0),ps(1),ps(4),ps(5))
|
||||||
rxdatap(i4)=r4
|
r4=max(ps(4),ps(5),ps(6),ps(7))-max(ps(0),ps(1),ps(2),ps(3))
|
||||||
rxdatap(i2)=r2
|
bmeta(i4)=r4
|
||||||
rxdatap(i1)=r1
|
bmeta(i2)=r2
|
||||||
|
bmeta(i1)=r1
|
||||||
|
bmetap(i4)=r4
|
||||||
|
bmetap(i2)=r2
|
||||||
|
bmetap(i1)=r1
|
||||||
|
|
||||||
if(nQSOProgress .eq. 0 .or. nQSOProgress .eq. 5) then
|
if(nQSOProgress .eq. 0 .or. nQSOProgress .eq. 5) then
|
||||||
! When bits 88:115 are set as ap bits, bit 115 lives in symbol 39 along
|
! When bits 88:115 are set as ap bits, bit 115 lives in symbol 39 along
|
||||||
! with no-ap bits 116 and 117. Take care of metrics for bits 116 and 117.
|
! with no-ap bits 116 and 117. Take care of metrics for bits 116 and 117.
|
||||||
if(j.eq.39) then ! take care of bits that live in symbol 39
|
if(j.eq.39) then ! take care of bits that live in symbol 39
|
||||||
if(apsym(28).lt.0) then
|
if(apsym(28).lt.0) then
|
||||||
rxdatap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
|
bmetap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
|
||||||
rxdatap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
|
bmetap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
|
||||||
else
|
else
|
||||||
rxdatap(i2)=max(ps(6),ps(7))-max(ps(4),ps(5))
|
bmetap(i2)=max(ps(6),ps(7))-max(ps(4),ps(5))
|
||||||
rxdatap(i1)=max(ps(5),ps(7))-max(ps(4),ps(6))
|
bmetap(i1)=max(ps(5),ps(7))-max(ps(4),ps(6))
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@ -187,43 +186,34 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
|||||||
! with ap bits 116 and 117. Take care of metric for bit 115.
|
! with ap bits 116 and 117. Take care of metric for bit 115.
|
||||||
! if(j.eq.39) then ! take care of bit 115
|
! if(j.eq.39) then ! take care of bit 115
|
||||||
! iii=2*(apsym(29)+1)/2 + (apsym(30)+1)/2 ! known values of bits 116 & 117
|
! iii=2*(apsym(29)+1)/2 + (apsym(30)+1)/2 ! known values of bits 116 & 117
|
||||||
! if(iii.eq.0) rxdatap(i4)=ps(4)-ps(0)
|
! if(iii.eq.0) bmetap(i4)=ps(4)-ps(0)
|
||||||
! if(iii.eq.1) rxdatap(i4)=ps(5)-ps(1)
|
! if(iii.eq.1) bmetap(i4)=ps(5)-ps(1)
|
||||||
! if(iii.eq.2) rxdatap(i4)=ps(6)-ps(2)
|
! if(iii.eq.2) bmetap(i4)=ps(6)-ps(2)
|
||||||
! if(iii.eq.3) rxdatap(i4)=ps(7)-ps(3)
|
! if(iii.eq.3) bmetap(i4)=ps(7)-ps(3)
|
||||||
! endif
|
! endif
|
||||||
|
|
||||||
! bit 144 lives in symbol 48 and will be 1 if it is set as an ap bit.
|
! bit 144 lives in symbol 48 and will be 1 if it is set as an ap bit.
|
||||||
! take care of metrics for bits 142 and 143
|
! take care of metrics for bits 142 and 143
|
||||||
if(j.eq.48) then ! bit 144 is always 1
|
if(j.eq.48) then ! bit 144 is always 1
|
||||||
rxdatap(i4)=max(ps(5),ps(7))-max(ps(1),ps(3))
|
bmetap(i4)=max(ps(5),ps(7))-max(ps(1),ps(3))
|
||||||
rxdatap(i2)=max(ps(3),ps(7))-max(ps(1),ps(5))
|
bmetap(i2)=max(ps(3),ps(7))-max(ps(1),ps(5))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
! bit 154 lives in symbol 52 and will be 0 if it is set as an ap bit
|
! bit 154 lives in symbol 52 and will be 0 if it is set as an ap bit
|
||||||
! take care of metrics for bits 155 and 156
|
! take care of metrics for bits 155 and 156
|
||||||
if(j.eq.52) then ! bit 154 will be 0 if it is set as an ap bit.
|
if(j.eq.52) then ! bit 154 will be 0 if it is set as an ap bit.
|
||||||
rxdatap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
|
bmetap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
|
||||||
rxdatap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
|
bmetap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
enddo
|
enddo
|
||||||
|
|
||||||
rxav=sum(rxdata)/(3.0*ND)
|
call normalizebmet(bmeta,3*ND)
|
||||||
rx2av=sum(rxdata*rxdata)/(3.0*ND)
|
call normalizebmet(bmetap,3*ND)
|
||||||
var=rx2av-rxav*rxav
|
|
||||||
if( var .gt. 0.0 ) then
|
|
||||||
rxsig=sqrt(var)
|
|
||||||
else
|
|
||||||
rxsig=sqrt(rx2av)
|
|
||||||
endif
|
|
||||||
rxdata=rxdata/rxsig
|
|
||||||
! Let's just assume that rxsig is OK for rxdatap too...
|
|
||||||
rxdatap=rxdatap/rxsig
|
|
||||||
|
|
||||||
ss=0.84
|
ss=0.84
|
||||||
llr0=2.0*rxdata/(ss*ss)
|
llr0=2.0*bmeta/(ss*ss)
|
||||||
llra=2.0*rxdatap/(ss*ss) ! llr's for use with ap
|
llra=2.0*bmetap/(ss*ss) ! llr's for use with ap
|
||||||
apmag=4.0
|
apmag=4.0
|
||||||
|
|
||||||
! pass #
|
! pass #
|
||||||
@ -245,11 +235,8 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
|||||||
do ipass=1,npasses
|
do ipass=1,npasses
|
||||||
|
|
||||||
llr=llr0
|
llr=llr0
|
||||||
if(ipass.ne.2 .and. ipass.ne.3) nblank=0
|
if(ipass.eq.2) llr(1:24)=0.
|
||||||
if(ipass.eq.2) nblank=24
|
if(ipass.eq.3) llr(1:48)=0.
|
||||||
if(ipass.eq.3) nblank=48
|
|
||||||
if(nblank.gt.0) llr(1:nblank)=0.
|
|
||||||
|
|
||||||
if(ipass.le.3) then
|
if(ipass.le.3) then
|
||||||
apmask=0
|
apmask=0
|
||||||
llrap=llr
|
llrap=llr
|
||||||
@ -308,23 +295,24 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
|||||||
call timer('bpd174 ',1)
|
call timer('bpd174 ',1)
|
||||||
dmin=0.0
|
dmin=0.0
|
||||||
if(ndepth.eq.3 .and. nharderrors.lt.0) then
|
if(ndepth.eq.3 .and. nharderrors.lt.0) then
|
||||||
norder=1
|
ndeep=3
|
||||||
if(abs(nfqso-f1).le.napwid .or. abs(nftx-f1).le.napwid) then
|
if(abs(nfqso-f1).le.napwid .or. abs(nftx-f1).le.napwid) then
|
||||||
if(ipass.le.3 .and. .not.nagain) then
|
if((ipass.eq.2 .or. ipass.eq.3) .and. .not.nagain) then
|
||||||
norder=2
|
ndeep=3
|
||||||
else ! norder=3 for nagain and AP decodes
|
else
|
||||||
norder=3
|
ndeep=4
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
if(nagain) ndeep=5
|
||||||
call timer('osd174 ',0)
|
call timer('osd174 ',0)
|
||||||
call osd174(llrap,apmask,norder,decoded,cw,nharderrors,dmin)
|
call osd174(llrap,apmask,ndeep,decoded,cw,nharderrors,dmin)
|
||||||
call timer('osd174 ',1)
|
call timer('osd174 ',1)
|
||||||
endif
|
endif
|
||||||
nbadcrc=1
|
nbadcrc=1
|
||||||
message=' '
|
message=' '
|
||||||
xsnr=-99.0
|
xsnr=-99.0
|
||||||
if(count(cw.eq.0).eq.174) cycle !Reject the all-zero codeword
|
if(count(cw.eq.0).eq.174) cycle !Reject the all-zero codeword
|
||||||
if(any(decoded(75:75).ne.0)) cycle !Reject if any of the 3 extra bits are nonzero
|
if(any(decoded(73:75).ne.0)) cycle !Reject if any of the 3 extra bits are nonzero
|
||||||
if(nharderrors.ge.0 .and. nharderrors+dmin.lt.60.0 .and. &
|
if(nharderrors.ge.0 .and. nharderrors+dmin.lt.60.0 .and. &
|
||||||
.not.(sync.lt.2.0 .and. nharderrors.gt.35) .and. &
|
.not.(sync.lt.2.0 .and. nharderrors.gt.35) .and. &
|
||||||
.not.(ipass.gt.1 .and. nharderrors.gt.39) .and. &
|
.not.(ipass.gt.1 .and. nharderrors.gt.39) .and. &
|
||||||
@ -349,6 +337,12 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
|||||||
xsnr=0.001
|
xsnr=0.001
|
||||||
if(xnoi.gt.0 .and. xnoi.lt.xsig) xsnr=xsig/xnoi-1.0
|
if(xnoi.gt.0 .and. xnoi.lt.xsig) xsnr=xsig/xnoi-1.0
|
||||||
xsnr=10.0*log10(xsnr)-27.0
|
xsnr=10.0*log10(xsnr)-27.0
|
||||||
|
!###
|
||||||
|
xsnr2=db(xsig/xbase - 1.0) - 32.0
|
||||||
|
! write(52,3052) f1,xdt,xsig,xnoi,xbase,xsnr,xsnr2
|
||||||
|
!3052 format(7f10.2)
|
||||||
|
xsnr=xsnr2
|
||||||
|
!###
|
||||||
if(xsnr .lt. -24.0) xsnr=-24.0
|
if(xsnr .lt. -24.0) xsnr=-24.0
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
@ -356,3 +350,18 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
|||||||
|
|
||||||
return
|
return
|
||||||
end subroutine ft8b
|
end subroutine ft8b
|
||||||
|
|
||||||
|
subroutine normalizebmet(bmet,n)
|
||||||
|
real bmet(n)
|
||||||
|
|
||||||
|
bmetav=sum(bmet)/real(n)
|
||||||
|
bmet2av=sum(bmet*bmet)/real(n)
|
||||||
|
var=bmet2av-bmetav*bmetav
|
||||||
|
if( var .gt. 0.0 ) then
|
||||||
|
bmetsig=sqrt(var)
|
||||||
|
else
|
||||||
|
bmetsig=sqrt(bmet2av)
|
||||||
|
endif
|
||||||
|
bmet=bmet/bmetsig
|
||||||
|
return
|
||||||
|
end subroutine normalizebmet
|
||||||
|
@ -39,16 +39,16 @@ nmpcbad=0 ! Used to collect the number of errors in the message+crc part of the
|
|||||||
|
|
||||||
nargs=iargc()
|
nargs=iargc()
|
||||||
if(nargs.ne.4) then
|
if(nargs.ne.4) then
|
||||||
print*,'Usage: ldpcsim niter norder #trials s '
|
print*,'Usage: ldpcsim niter ndepth #trials s '
|
||||||
print*,'eg: ldpcsim 10 2 1000 0.84'
|
print*,'eg: ldpcsim 10 2 1000 0.84'
|
||||||
print*,'belief propagation iterations: niter, ordered-statistics order: norder'
|
print*,'belief propagation iterations: niter, ordered-statistics depth: ndepth'
|
||||||
print*,'If s is negative, then value is ignored and sigma is calculated from SNR.'
|
print*,'If s is negative, then value is ignored and sigma is calculated from SNR.'
|
||||||
return
|
return
|
||||||
endif
|
endif
|
||||||
call getarg(1,arg)
|
call getarg(1,arg)
|
||||||
read(arg,*) max_iterations
|
read(arg,*) max_iterations
|
||||||
call getarg(2,arg)
|
call getarg(2,arg)
|
||||||
read(arg,*) norder
|
read(arg,*) ndepth
|
||||||
call getarg(3,arg)
|
call getarg(3,arg)
|
||||||
read(arg,*) ntrials
|
read(arg,*) ntrials
|
||||||
call getarg(4,arg)
|
call getarg(4,arg)
|
||||||
@ -128,13 +128,14 @@ allocate ( rxdata(N), llr(N) )
|
|||||||
|
|
||||||
call encode174(msgbits,codeword)
|
call encode174(msgbits,codeword)
|
||||||
call init_random_seed()
|
call init_random_seed()
|
||||||
call sgran()
|
! call sgran()
|
||||||
|
|
||||||
write(*,*) 'codeword'
|
write(*,*) 'codeword'
|
||||||
write(*,'(22(8i1,1x))') codeword
|
write(*,'(22(8i1,1x))') codeword
|
||||||
|
|
||||||
write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma"
|
write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma"
|
||||||
do idb = 20,-10,-1
|
do idb = 20,-10,-1
|
||||||
|
!do idb = -3,-3,-1
|
||||||
db=idb/2.0-1.0
|
db=idb/2.0-1.0
|
||||||
sigma=1/sqrt( 2*(10**(db/10.0)) )
|
sigma=1/sqrt( 2*(10**(db/10.0)) )
|
||||||
ngood=0
|
ngood=0
|
||||||
@ -188,8 +189,8 @@ do idb = 20,-10,-1
|
|||||||
apmask(colorder(174-87+1:174-87+nap)+1)=1
|
apmask(colorder(174-87+1:174-87+nap)+1)=1
|
||||||
|
|
||||||
! max_iterations is max number of belief propagation iterations
|
! max_iterations is max number of belief propagation iterations
|
||||||
call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors)
|
call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors,niterations)
|
||||||
if( norder .ge. 0 .and. nharderrors .lt. 0 ) call osd174(llr, norder, decoded, cw, nharderrors)
|
if( ndepth .ge. 0 .and. nharderrors .lt. 0 ) call osd174(llr, apmask, ndepth, decoded, cw, nharderrors, dmin)
|
||||||
! If the decoder finds a valid codeword, nharderrors will be .ge. 0.
|
! If the decoder finds a valid codeword, nharderrors will be .ge. 0.
|
||||||
if( nharderrors .ge. 0 ) then
|
if( nharderrors .ge. 0 ) then
|
||||||
call extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent)
|
call extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent)
|
||||||
@ -206,7 +207,6 @@ do idb = 20,-10,-1
|
|||||||
endif
|
endif
|
||||||
enddo
|
enddo
|
||||||
nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1
|
nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1
|
||||||
|
|
||||||
if( ncrcflag .eq. 1 ) then
|
if( ncrcflag .eq. 1 ) then
|
||||||
if( nueflag .eq. 0 ) then
|
if( nueflag .eq. 0 ) then
|
||||||
ngood=ngood+1
|
ngood=ngood+1
|
||||||
@ -217,7 +217,7 @@ do idb = 20,-10,-1
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
enddo
|
enddo
|
||||||
baud=12000/2048
|
baud=12000/1920
|
||||||
snr2500=db+10.0*log10((baud/2500.0))
|
snr2500=db+10.0*log10((baud/2500.0))
|
||||||
pberr=real(nberr)/(real(ntrials*N))
|
pberr=real(nberr)/(real(ntrials*N))
|
||||||
write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,snr2500,ngood,nue,nbadcrc,ss,pberr
|
write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,snr2500,ngood,nue,nbadcrc,ss,pberr
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
subroutine osd174(llr,apmask,norder,decoded,cw,nhardmin,dmin)
|
subroutine osd174(llr,apmask,ndeep,decoded,cw,nhardmin,dmin)
|
||||||
!
|
!
|
||||||
! An ordered-statistics decoder for the (174,87) code.
|
! An ordered-statistics decoder for the (174,87) code.
|
||||||
!
|
!
|
||||||
@ -7,15 +7,15 @@ include "ldpc_174_87_params.f90"
|
|||||||
integer*1 apmask(N),apmaskr(N)
|
integer*1 apmask(N),apmaskr(N)
|
||||||
integer*1 gen(K,N)
|
integer*1 gen(K,N)
|
||||||
integer*1 genmrb(K,N),g2(N,K)
|
integer*1 genmrb(K,N),g2(N,K)
|
||||||
integer*1 temp(K),m0(K),me(K),mi(K)
|
integer*1 temp(K),m0(K),me(K),mi(K),misub(K),e2sub(N-K),e2(N-K),ui(N-K)
|
||||||
|
integer*1 r2pat(N-K)
|
||||||
integer indices(N),nxor(N)
|
integer indices(N),nxor(N)
|
||||||
integer*1 cw(N),ce(N),c0(N),hdec(N)
|
integer*1 cw(N),ce(N),c0(N),hdec(N)
|
||||||
integer*1 decoded(K)
|
integer*1 decoded(K)
|
||||||
integer indx(N)
|
integer indx(N)
|
||||||
real llr(N),rx(N),absrx(N)
|
real llr(N),rx(N),absrx(N)
|
||||||
logical first
|
logical first,reset
|
||||||
data first/.true./
|
data first/.true./
|
||||||
|
|
||||||
save first,gen
|
save first,gen
|
||||||
|
|
||||||
if( first ) then ! fill the generator matrix
|
if( first ) then ! fill the generator matrix
|
||||||
@ -35,30 +35,26 @@ if( first ) then ! fill the generator matrix
|
|||||||
first=.false.
|
first=.false.
|
||||||
endif
|
endif
|
||||||
|
|
||||||
! re-order received vector to place systematic msg bits at the end
|
! Re-order received vector to place systematic msg bits at the end.
|
||||||
rx=llr(colorder+1)
|
rx=llr(colorder+1)
|
||||||
apmaskr=apmask(colorder+1)
|
apmaskr=apmask(colorder+1)
|
||||||
|
|
||||||
|
! Hard decisions on the received word.
|
||||||
! hard decode the received word
|
|
||||||
hdec=0
|
hdec=0
|
||||||
where(rx .ge. 0) hdec=1
|
where(rx .ge. 0) hdec=1
|
||||||
|
|
||||||
! use magnitude of received symbols as a measure of reliability.
|
! Use magnitude of received symbols as a measure of reliability.
|
||||||
absrx=abs(rx)
|
absrx=abs(rx)
|
||||||
call indexx(absrx,N,indx)
|
call indexx(absrx,N,indx)
|
||||||
|
|
||||||
! re-order the columns of the generator matrix in order of decreasing reliability.
|
! Re-order the columns of the generator matrix in order of decreasing reliability.
|
||||||
do i=1,N
|
do i=1,N
|
||||||
genmrb(1:K,i)=gen(1:K,indx(N+1-i))
|
genmrb(1:K,i)=gen(1:K,indx(N+1-i))
|
||||||
indices(i)=indx(N+1-i)
|
indices(i)=indx(N+1-i)
|
||||||
enddo
|
enddo
|
||||||
|
|
||||||
! do gaussian elimination to create a generator matrix with the most reliable
|
! Do gaussian elimination to create a generator matrix with the most reliable
|
||||||
! received bits in positions 1:K in order of decreasing reliability (more or less).
|
! received bits in positions 1:K in order of decreasing reliability (more or less).
|
||||||
! reliability will not be strictly decreasing because column re-ordering is needed
|
|
||||||
! to put the generator matrix in systematic form. the "indices" array tracks
|
|
||||||
! column permutations caused by reliability sorting and gaussian elimination.
|
|
||||||
do id=1,K ! diagonal element indices
|
do id=1,K ! diagonal element indices
|
||||||
do icol=id,K+20 ! The 20 is ad hoc - beware
|
do icol=id,K+20 ! The 20 is ad hoc - beware
|
||||||
iflag=0
|
iflag=0
|
||||||
@ -87,8 +83,8 @@ g2=transpose(genmrb)
|
|||||||
! The hard decisions for the K MRB bits define the order 0 message, m0.
|
! The hard decisions for the K MRB bits define the order 0 message, m0.
|
||||||
! Encode m0 using the modified generator matrix to find the "order 0" codeword.
|
! Encode m0 using the modified generator matrix to find the "order 0" codeword.
|
||||||
! Flip various combinations of bits in m0 and re-encode to generate a list of
|
! Flip various combinations of bits in m0 and re-encode to generate a list of
|
||||||
! codewords. Test all such codewords against the received word to decide which
|
! codewords. Return the member of the list that has the smallest Euclidean
|
||||||
! codeword is most likely to be correct.
|
! distance to the received word.
|
||||||
|
|
||||||
hdec=hdec(indices) ! hard decisions from received symbols
|
hdec=hdec(indices) ! hard decisions from received symbols
|
||||||
m0=hdec(1:K) ! zero'th order message
|
m0=hdec(1:K) ! zero'th order message
|
||||||
@ -96,55 +92,170 @@ absrx=absrx(indices)
|
|||||||
rx=rx(indices)
|
rx=rx(indices)
|
||||||
apmaskr=apmaskr(indices)
|
apmaskr=apmaskr(indices)
|
||||||
|
|
||||||
s1=sum(absrx(1:K))
|
|
||||||
s2=sum(absrx(K+1:N))
|
|
||||||
xlam=7.0 ! larger values reject more error patterns
|
|
||||||
rho=s1/(s1+xlam*s2)
|
|
||||||
call mrbencode(m0,c0,g2,N,K)
|
call mrbencode(m0,c0,g2,N,K)
|
||||||
nxor=ieor(c0,hdec)
|
nxor=ieor(c0,hdec)
|
||||||
nhardmin=sum(nxor)
|
nhardmin=sum(nxor)
|
||||||
dmin=sum(nxor*absrx)
|
dmin=sum(nxor*absrx)
|
||||||
thresh=rho*dmin
|
|
||||||
|
|
||||||
cw=c0
|
cw=c0
|
||||||
nt=0
|
ntotal=0
|
||||||
nrejected=0
|
nrejected=0
|
||||||
do iorder=1,norder
|
|
||||||
mi(1:K-iorder)=0
|
if(ndeep.eq.0) goto 998 ! norder=0
|
||||||
mi(K-iorder+1:K)=1
|
if(ndeep.gt.5) ndeep=5
|
||||||
iflag=0
|
if( ndeep.eq. 1) then
|
||||||
do while(iflag .ge. 0 )
|
nord=1
|
||||||
if(all(iand(apmaskr(1:K),mi).eq.0)) then ! reject patterns with ap bits
|
npre1=0
|
||||||
dpat=sum(mi*absrx(1:K))
|
npre2=0
|
||||||
nt=nt+1
|
nt=40
|
||||||
if( dpat .lt. thresh ) then ! reject unlikely error patterns
|
ntheta=12
|
||||||
me=ieor(m0,mi)
|
elseif(ndeep.eq.2) then
|
||||||
call mrbencode(me,ce,g2,N,K)
|
nord=1
|
||||||
nxor=ieor(ce,hdec)
|
npre1=1
|
||||||
dd=sum(nxor*absrx)
|
npre2=0
|
||||||
if( dd .lt. dmin ) then
|
nt=40
|
||||||
dmin=dd
|
ntheta=12
|
||||||
cw=ce
|
elseif(ndeep.eq.3) then
|
||||||
nhardmin=sum(nxor)
|
nord=1
|
||||||
thresh=rho*dmin
|
npre1=1
|
||||||
endif
|
npre2=1
|
||||||
|
nt=40
|
||||||
|
ntheta=12
|
||||||
|
ntau=14
|
||||||
|
elseif(ndeep.eq.4) then
|
||||||
|
nord=2
|
||||||
|
npre1=1
|
||||||
|
npre2=0
|
||||||
|
nt=40
|
||||||
|
ntheta=12
|
||||||
|
ntau=19
|
||||||
|
elseif(ndeep.eq.5) then
|
||||||
|
nord=2
|
||||||
|
npre1=1
|
||||||
|
npre2=1
|
||||||
|
nt=40
|
||||||
|
ntheta=12
|
||||||
|
ntau=19
|
||||||
|
endif
|
||||||
|
|
||||||
|
do iorder=1,nord
|
||||||
|
if( iorder.eq. 1 ) then
|
||||||
|
misub(1:K-1)=0
|
||||||
|
misub(K)=1
|
||||||
|
iflag=K
|
||||||
|
elseif( iorder.eq. 2 ) then
|
||||||
|
misub(1:K-2)=0
|
||||||
|
misub(K-1:K)=1
|
||||||
|
iflag=K-1
|
||||||
|
endif
|
||||||
|
do while(iflag .ge.0)
|
||||||
|
if(iorder.eq.nord .and. npre1.eq.0) then
|
||||||
|
iend=iflag
|
||||||
else
|
else
|
||||||
nrejected=nrejected+1
|
iend=1
|
||||||
endif
|
endif
|
||||||
endif
|
do n1=iflag,iend,-1
|
||||||
! get the next test error pattern, iflag will go negative
|
mi=misub
|
||||||
! when the last pattern with weight iorder has been generated
|
mi(n1)=1
|
||||||
call nextpat(mi,k,iorder,iflag)
|
if(any(iand(apmaskr(1:K),mi).eq.1)) cycle
|
||||||
enddo
|
ntotal=ntotal+1
|
||||||
|
me=ieor(m0,mi)
|
||||||
|
if(n1.eq.iflag) then
|
||||||
|
call mrbencode(me,ce,g2,N,K)
|
||||||
|
e2sub=ieor(ce(K+1:N),hdec(K+1:N))
|
||||||
|
e2=e2sub
|
||||||
|
nd1Kpt=sum(e2sub(1:nt))+1
|
||||||
|
d1=sum(ieor(me(1:K),hdec(1:K))*absrx(1:K))
|
||||||
|
else
|
||||||
|
e2=ieor(e2sub,g2(K+1:N,n1))
|
||||||
|
nd1Kpt=sum(e2(1:nt))+2
|
||||||
|
endif
|
||||||
|
if(nd1Kpt .le. ntheta) then
|
||||||
|
call mrbencode(me,ce,g2,N,K)
|
||||||
|
nxor=ieor(ce,hdec)
|
||||||
|
if(n1.eq.iflag) then
|
||||||
|
dd=d1+sum(e2sub*absrx(K+1:N))
|
||||||
|
else
|
||||||
|
dd=d1+ieor(ce(n1),hdec(n1))*absrx(n1)+sum(e2*absrx(K+1:N))
|
||||||
|
endif
|
||||||
|
if( dd .lt. dmin ) then
|
||||||
|
dmin=dd
|
||||||
|
cw=ce
|
||||||
|
nhardmin=sum(nxor)
|
||||||
|
nd1Kptbest=nd1Kpt
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
nrejected=nrejected+1
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
! Get the next test error pattern, iflag will go negative
|
||||||
|
! when the last pattern with weight iorder has been generated.
|
||||||
|
call nextpat(misub,k,iorder,iflag)
|
||||||
|
enddo
|
||||||
enddo
|
enddo
|
||||||
|
|
||||||
!write(*,*) 'nhardmin ',nhardmin
|
if(npre2.eq.1) then
|
||||||
!write(*,*) 'total patterns ',nt,' number rejected ',nrejected
|
reset=.true.
|
||||||
|
ntotal=0
|
||||||
|
do i1=K,1,-1
|
||||||
|
do i2=i1-1,1,-1
|
||||||
|
ntotal=ntotal+1
|
||||||
|
mi(1:ntau)=ieor(g2(K+1:K+ntau,i1),g2(K+1:K+ntau,i2))
|
||||||
|
call boxit(reset,mi(1:ntau),ntau,ntotal,i1,i2)
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
|
||||||
! re-order the codeword to place message bits at the end
|
ncount2=0
|
||||||
|
ntotal2=0
|
||||||
|
reset=.true.
|
||||||
|
! Now run through again and do the second pre-processing rule
|
||||||
|
if(nord.eq.1) then
|
||||||
|
misub(1:K-1)=0
|
||||||
|
misub(K)=1
|
||||||
|
iflag=K
|
||||||
|
elseif(nord.eq.2) then
|
||||||
|
misub(1:K-1)=0
|
||||||
|
misub(K-1:K)=1
|
||||||
|
iflag=K-1
|
||||||
|
endif
|
||||||
|
do while(iflag .ge.0)
|
||||||
|
me=ieor(m0,misub)
|
||||||
|
call mrbencode(me,ce,g2,N,K)
|
||||||
|
e2sub=ieor(ce(K+1:N),hdec(K+1:N))
|
||||||
|
do i2=0,ntau
|
||||||
|
ntotal2=ntotal2+1
|
||||||
|
ui=0
|
||||||
|
if(i2.gt.0) ui(i2)=1
|
||||||
|
r2pat=ieor(e2sub,ui)
|
||||||
|
778 continue
|
||||||
|
call fetchit(reset,r2pat(1:ntau),ntau,in1,in2)
|
||||||
|
if(in1.gt.0.and.in2.gt.0) then
|
||||||
|
ncount2=ncount2+1
|
||||||
|
mi=misub
|
||||||
|
mi(in1)=1
|
||||||
|
mi(in2)=1
|
||||||
|
if(sum(mi).lt.nord+npre1+npre2.or.any(iand(apmaskr(1:K),mi).eq.1)) cycle
|
||||||
|
me=ieor(m0,mi)
|
||||||
|
call mrbencode(me,ce,g2,N,K)
|
||||||
|
nxor=ieor(ce,hdec)
|
||||||
|
dd=sum(nxor*absrx)
|
||||||
|
if( dd .lt. dmin ) then
|
||||||
|
dmin=dd
|
||||||
|
cw=ce
|
||||||
|
nhardmin=sum(nxor)
|
||||||
|
endif
|
||||||
|
goto 778
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
call nextpat(misub,K,nord,iflag)
|
||||||
|
enddo
|
||||||
|
endif
|
||||||
|
|
||||||
|
998 continue
|
||||||
|
! Re-order the codeword to place message bits at the end.
|
||||||
cw(indices)=cw
|
cw(indices)=cw
|
||||||
hdec(indices)=hdec
|
hdec(indices)=hdec
|
||||||
decoded=cw(M+1:N)
|
decoded=cw(K+1:N)
|
||||||
cw(colorder+1)=cw ! put the codeword back into received-word order
|
cw(colorder+1)=cw ! put the codeword back into received-word order
|
||||||
return
|
return
|
||||||
end subroutine osd174
|
end subroutine osd174
|
||||||
@ -181,6 +292,86 @@ subroutine nextpat(mi,k,iorder,iflag)
|
|||||||
ms(k-nz+1:k)=1
|
ms(k-nz+1:k)=1
|
||||||
endif
|
endif
|
||||||
mi=ms
|
mi=ms
|
||||||
iflag=ind
|
do i=1,k ! iflag will point to the lowest-index 1 in mi
|
||||||
|
if(mi(i).eq.1) then
|
||||||
|
iflag=i
|
||||||
|
exit
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
return
|
return
|
||||||
end subroutine nextpat
|
end subroutine nextpat
|
||||||
|
|
||||||
|
subroutine boxit(reset,e2,ntau,npindex,i1,i2)
|
||||||
|
integer*1 e2(1:ntau)
|
||||||
|
integer indexes(4000,2),fp(0:525000),np(4000)
|
||||||
|
logical reset
|
||||||
|
common/boxes/indexes,fp,np
|
||||||
|
|
||||||
|
if(reset) then
|
||||||
|
patterns=-1
|
||||||
|
fp=-1
|
||||||
|
np=-1
|
||||||
|
sc=-1
|
||||||
|
indexes=-1
|
||||||
|
reset=.false.
|
||||||
|
endif
|
||||||
|
|
||||||
|
indexes(npindex,1)=i1
|
||||||
|
indexes(npindex,2)=i2
|
||||||
|
ipat=0
|
||||||
|
do i=1,ntau
|
||||||
|
if(e2(i).eq.1) then
|
||||||
|
ipat=ipat+ishft(1,ntau-i)
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
|
||||||
|
ip=fp(ipat) ! see what's currently stored in fp(ipat)
|
||||||
|
if(ip.eq.-1) then
|
||||||
|
fp(ipat)=npindex
|
||||||
|
else
|
||||||
|
do while (np(ip).ne.-1)
|
||||||
|
ip=np(ip)
|
||||||
|
enddo
|
||||||
|
np(ip)=npindex
|
||||||
|
endif
|
||||||
|
return
|
||||||
|
end subroutine boxit
|
||||||
|
|
||||||
|
subroutine fetchit(reset,e2,ntau,i1,i2)
|
||||||
|
integer indexes(4000,2),fp(0:525000),np(4000)
|
||||||
|
integer lastpat
|
||||||
|
integer*1 e2(ntau)
|
||||||
|
logical reset
|
||||||
|
common/boxes/indexes,fp,np
|
||||||
|
save lastpat,inext
|
||||||
|
|
||||||
|
if(reset) then
|
||||||
|
lastpat=-1
|
||||||
|
reset=.false.
|
||||||
|
endif
|
||||||
|
|
||||||
|
ipat=0
|
||||||
|
do i=1,ntau
|
||||||
|
if(e2(i).eq.1) then
|
||||||
|
ipat=ipat+ishft(1,ntau-i)
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
index=fp(ipat)
|
||||||
|
|
||||||
|
if(lastpat.ne.ipat .and. index.gt.0) then ! return first set of indices
|
||||||
|
i1=indexes(index,1)
|
||||||
|
i2=indexes(index,2)
|
||||||
|
inext=np(index)
|
||||||
|
elseif(lastpat.eq.ipat .and. inext.gt.0) then
|
||||||
|
i1=indexes(inext,1)
|
||||||
|
i2=indexes(inext,2)
|
||||||
|
inext=np(inext)
|
||||||
|
else
|
||||||
|
i1=-1
|
||||||
|
i2=-1
|
||||||
|
inext=-1
|
||||||
|
endif
|
||||||
|
lastpat=ipat
|
||||||
|
return
|
||||||
|
end subroutine fetchit
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand)
|
subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand,sbase)
|
||||||
|
|
||||||
include 'ft8_params.f90'
|
include 'ft8_params.f90'
|
||||||
! Search over +/- 1.5s relative to 0.5s TX start time.
|
! Search over +/- 1.5s relative to 0.5s TX start time.
|
||||||
@ -6,6 +6,7 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand)
|
|||||||
complex cx(0:NH1)
|
complex cx(0:NH1)
|
||||||
real s(NH1,NHSYM)
|
real s(NH1,NHSYM)
|
||||||
real savg(NH1)
|
real savg(NH1)
|
||||||
|
real sbase(NH1)
|
||||||
real x(NFFT1)
|
real x(NFFT1)
|
||||||
real sync2d(NH1,-JZ:JZ)
|
real sync2d(NH1,-JZ:JZ)
|
||||||
real red(NH1)
|
real red(NH1)
|
||||||
@ -35,7 +36,8 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand)
|
|||||||
enddo
|
enddo
|
||||||
savg=savg + s(1:NH1,j) !Average spectrum
|
savg=savg + s(1:NH1,j) !Average spectrum
|
||||||
enddo
|
enddo
|
||||||
savg=savg/NHSYM
|
call baseline(savg,nfa,nfb,sbase)
|
||||||
|
! savg=savg/NHSYM
|
||||||
! do i=1,NH1
|
! do i=1,NH1
|
||||||
! write(51,3051) i*df,savg(i),db(savg(i))
|
! write(51,3051) i*df,savg(i),db(savg(i))
|
||||||
!3051 format(f10.3,e12.3,f12.3)
|
!3051 format(f10.3,e12.3,f12.3)
|
||||||
|
@ -34,6 +34,7 @@ contains
|
|||||||
class(ft8_decoder), intent(inout) :: this
|
class(ft8_decoder), intent(inout) :: this
|
||||||
procedure(ft8_decode_callback) :: callback
|
procedure(ft8_decode_callback) :: callback
|
||||||
real s(NH1,NHSYM)
|
real s(NH1,NHSYM)
|
||||||
|
real sbase(NH1)
|
||||||
real candidate(3,200)
|
real candidate(3,200)
|
||||||
real dd(15*12000)
|
real dd(15*12000)
|
||||||
logical, intent(in) :: lapon,nagain
|
logical, intent(in) :: lapon,nagain
|
||||||
@ -67,63 +68,62 @@ contains
|
|||||||
! For now:
|
! For now:
|
||||||
! ndepth=1: no subtraction, 1 pass, belief propagation only
|
! ndepth=1: no subtraction, 1 pass, belief propagation only
|
||||||
! ndepth=2: subtraction, 2 passes, belief propagation only
|
! ndepth=2: subtraction, 2 passes, belief propagation only
|
||||||
! ndepth=3: subtraction, 2 passes, bp+osd2 at and near nfqso
|
! ndepth=3: subtraction, 2 passes, bp+osd
|
||||||
if(ndepth.eq.1) npass=1
|
if(ndepth.eq.1) npass=1
|
||||||
if(ndepth.ge.2) npass=2
|
if(ndepth.ge.2) npass=3
|
||||||
do ipass=1,npass
|
do ipass=1,npass
|
||||||
newdat=.true. ! Is this a problem? I hijacked newdat.
|
newdat=.true. ! Is this a problem? I hijacked newdat.
|
||||||
|
syncmin=1.5
|
||||||
if(ipass.eq.1) then
|
if(ipass.eq.1) then
|
||||||
lsubtract=.true.
|
lsubtract=.true.
|
||||||
if(ndepth.eq.1) lsubtract=.false.
|
if(ndepth.eq.1) lsubtract=.false.
|
||||||
syncmin=1.5
|
elseif(ipass.eq.2) then
|
||||||
else
|
n2=ndecodes
|
||||||
|
if(ndecodes.eq.0) cycle
|
||||||
|
lsubtract=.true.
|
||||||
|
elseif(ipass.eq.3) then
|
||||||
|
if((ndecodes-n2).eq.0) cycle
|
||||||
lsubtract=.false.
|
lsubtract=.false.
|
||||||
syncmin=1.5
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
call timer('sync8 ',0)
|
call timer('sync8 ',0)
|
||||||
call sync8(dd,ifa,ifb,syncmin,nfqso,s,candidate,ncand)
|
call sync8(dd,ifa,ifb,syncmin,nfqso,s,candidate,ncand,sbase)
|
||||||
call timer('sync8 ',1)
|
call timer('sync8 ',1)
|
||||||
do icand=1,ncand
|
do icand=1,ncand
|
||||||
sync=candidate(3,icand)
|
sync=candidate(3,icand)
|
||||||
f1=candidate(1,icand)
|
f1=candidate(1,icand)
|
||||||
xdt=candidate(2,icand)
|
xdt=candidate(2,icand)
|
||||||
|
xbase=10.0**(0.1*(sbase(nint(f1/3.125))-40.0))
|
||||||
nsnr0=min(99,nint(10.0*log10(sync) - 25.5)) !### empirical ###
|
nsnr0=min(99,nint(10.0*log10(sync) - 25.5)) !### empirical ###
|
||||||
call timer('ft8b ',0)
|
call timer('ft8b ',0)
|
||||||
call ft8b(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
call ft8b(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
||||||
lsubtract,nagain,iaptype,mygrid6,bcontest,sync,f1,xdt,apsym, &
|
lsubtract,nagain,iaptype,mygrid6,bcontest,sync,f1,xdt,xbase, &
|
||||||
nharderrors,dmin,nbadcrc,iappass,iera,message,xsnr)
|
apsym,nharderrors,dmin,nbadcrc,iappass,iera,message,xsnr)
|
||||||
nsnr=nint(xsnr)
|
nsnr=nint(xsnr)
|
||||||
xdt=xdt-0.5
|
xdt=xdt-0.5
|
||||||
hd=nharderrors+dmin
|
hd=nharderrors+dmin
|
||||||
call timer('ft8b ',1)
|
call timer('ft8b ',1)
|
||||||
if(nbadcrc.eq.0) then
|
if(nbadcrc.eq.0) then
|
||||||
call jtmsg(message,iflag)
|
! call jtmsg(message,iflag)
|
||||||
if(bcontest) call fix_contest_msg(mygrid6,message)
|
if(bcontest) call fix_contest_msg(mygrid6,message)
|
||||||
if(iand(iflag,16).ne.0) message(22:22)='?'
|
! if(iand(iflag,31).ne.0) message(22:22)='?'
|
||||||
if(iand(iflag,15).eq.0) then
|
ldupe=.false.
|
||||||
ldupe=.false.
|
do id=1,ndecodes
|
||||||
do id=1,ndecodes
|
if(message.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true.
|
||||||
if(message.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true.
|
enddo
|
||||||
enddo
|
if(.not.ldupe) then
|
||||||
if(.not.ldupe) then
|
ndecodes=ndecodes+1
|
||||||
ndecodes=ndecodes+1
|
allmessages(ndecodes)=message
|
||||||
allmessages(ndecodes)=message
|
allsnrs(ndecodes)=nsnr
|
||||||
allsnrs(ndecodes)=nsnr
|
endif
|
||||||
endif
|
! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
|
||||||
! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
|
! nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
|
||||||
! iflag,nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
|
! xdt,nint(f1),message
|
||||||
! xdt,nint(f1),message
|
!1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a22)
|
||||||
! flush(81)
|
! flush(81)
|
||||||
if(.not.ldupe .and. associated(this%callback)) then
|
if(.not.ldupe .and. associated(this%callback)) then
|
||||||
qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0]
|
qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0]
|
||||||
call this%callback(sync,nsnr,xdt,f1,message,iaptype,qual)
|
call this%callback(sync,nsnr,xdt,f1,message,iaptype,qual)
|
||||||
endif
|
|
||||||
else
|
|
||||||
write(19,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
|
|
||||||
iflag,nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
|
|
||||||
xdt,nint(f1),message
|
|
||||||
1004 format(i6.6,2i4,3i2,2i3,3f6.1,i4,f6.2,i5,2x,a22)
|
|
||||||
flush(19)
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
enddo
|
enddo
|
||||||
|
@ -18,7 +18,7 @@ void ADIF::init(QString const& filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString ADIF::_extractField(QString const& line, QString const& fieldName)
|
QString ADIF::_extractField(QString const& line, QString const& fieldName) const
|
||||||
{
|
{
|
||||||
int fieldNameIndex = line.indexOf(fieldName,0,Qt::CaseInsensitive);
|
int fieldNameIndex = line.indexOf(fieldName,0,Qt::CaseInsensitive);
|
||||||
if (fieldNameIndex >=0)
|
if (fieldNameIndex >=0)
|
||||||
@ -87,7 +87,7 @@ void ADIF::add(QString const& call, QString const& band, QString const& mode, QS
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return true if in the log same band and mode (where JT65 == JT9)
|
// return true if in the log same band and mode (where JT65 == JT9)
|
||||||
bool ADIF::match(QString const& call, QString const& band, QString const& mode)
|
bool ADIF::match(QString const& call, QString const& band, QString const& mode) const
|
||||||
{
|
{
|
||||||
QList<QSO> qsos = _data.values(call);
|
QList<QSO> qsos = _data.values(call);
|
||||||
if (qsos.size()>0)
|
if (qsos.size()>0)
|
||||||
@ -120,7 +120,7 @@ bool ADIF::match(QString const& call, QString const& band, QString const& mode)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<QString> ADIF::getCallList()
|
QList<QString> ADIF::getCallList() const
|
||||||
{
|
{
|
||||||
QList<QString> p;
|
QList<QString> p;
|
||||||
QMultiHash<QString,QSO>::const_iterator i = _data.constBegin();
|
QMultiHash<QString,QSO>::const_iterator i = _data.constBegin();
|
||||||
@ -132,7 +132,7 @@ QList<QString> ADIF::getCallList()
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ADIF::getCount()
|
int ADIF::getCount() const
|
||||||
{
|
{
|
||||||
return _data.size();
|
return _data.size();
|
||||||
}
|
}
|
||||||
|
@ -21,18 +21,18 @@ class QDateTime;
|
|||||||
class ADIF
|
class ADIF
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init(QString const& filename);
|
void init(QString const& filename);
|
||||||
void load();
|
void load();
|
||||||
void add(QString const& call, QString const& band, QString const& mode, QString const& date);
|
void add(QString const& call, QString const& band, QString const& mode, QString const& date);
|
||||||
bool match(QString const& call, QString const& band, QString const& mode);
|
bool match(QString const& call, QString const& band, QString const& mode) const;
|
||||||
QList<QString> getCallList();
|
QList<QString> getCallList() const;
|
||||||
int getCount();
|
int getCount() const;
|
||||||
|
|
||||||
// open ADIF file and append the QSO details. Return true on success
|
// open ADIF file and append the QSO details. Return true on success
|
||||||
bool addQSOToFile(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, QString const& band,
|
bool addQSOToFile(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, QString const& band,
|
||||||
QString const& comments, QString const& name, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid, QString const& m_txPower);
|
QString const& comments, QString const& name, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid, QString const& m_txPower);
|
||||||
|
|
||||||
static QString bandFromFrequency(double dialFreq);
|
static QString bandFromFrequency(double dialFreq);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct QSO
|
struct QSO
|
||||||
@ -43,7 +43,7 @@ class ADIF
|
|||||||
QMultiHash<QString, QSO> _data;
|
QMultiHash<QString, QSO> _data;
|
||||||
QString _filename;
|
QString _filename;
|
||||||
|
|
||||||
QString _extractField(QString const& line, QString const& fieldName);
|
QString _extractField(QString const& line, QString const& fieldName) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ void CountriesWorked::setAsWorked(const QString countryName)
|
|||||||
_data.insert(countryName,true);
|
_data.insert(countryName,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CountriesWorked::getHasWorked(const QString countryName)
|
bool CountriesWorked::getHasWorked(const QString countryName) const
|
||||||
{
|
{
|
||||||
if (_data.contains(countryName))
|
if (_data.contains(countryName))
|
||||||
return _data.value(countryName);
|
return _data.value(countryName);
|
||||||
@ -21,7 +21,7 @@ bool CountriesWorked::getHasWorked(const QString countryName)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CountriesWorked::getWorkedCount()
|
int CountriesWorked::getWorkedCount() const
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
foreach (bool value,_data)
|
foreach (bool value,_data)
|
||||||
@ -30,7 +30,7 @@ int CountriesWorked::getWorkedCount()
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CountriesWorked::getSize()
|
int CountriesWorked::getSize() const
|
||||||
{
|
{
|
||||||
return _data.count();
|
return _data.count();
|
||||||
}
|
}
|
||||||
|
@ -14,15 +14,15 @@
|
|||||||
|
|
||||||
class CountriesWorked
|
class CountriesWorked
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init(const QStringList countryNames);
|
void init(const QStringList countryNames);
|
||||||
void setAsWorked(const QString countryName);
|
void setAsWorked(const QString countryName);
|
||||||
bool getHasWorked(const QString countryName);
|
bool getHasWorked(const QString countryName) const;
|
||||||
int getWorkedCount();
|
int getWorkedCount() const;
|
||||||
int getSize();
|
int getSize() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<QString, bool> _data;
|
QHash<QString, bool> _data;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,7 +26,7 @@ void CountryDat::init(const QString filename)
|
|||||||
_data.clear();
|
_data.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString CountryDat::_extractName(const QString line)
|
QString CountryDat::_extractName(const QString line) const
|
||||||
{
|
{
|
||||||
int s1 = line.indexOf(':');
|
int s1 = line.indexOf(':');
|
||||||
if (s1>=0)
|
if (s1>=0)
|
||||||
@ -37,7 +37,7 @@ QString CountryDat::_extractName(const QString line)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void CountryDat::_removeBrackets(QString &line, const QString a, const QString b)
|
void CountryDat::_removeBrackets(QString &line, const QString a, const QString b) const
|
||||||
{
|
{
|
||||||
int s1 = line.indexOf(a);
|
int s1 = line.indexOf(a);
|
||||||
while (s1 >= 0)
|
while (s1 >= 0)
|
||||||
@ -48,7 +48,7 @@ void CountryDat::_removeBrackets(QString &line, const QString a, const QString b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList CountryDat::_extractPrefix(QString &line, bool &more)
|
QStringList CountryDat::_extractPrefix(QString &line, bool &more) const
|
||||||
{
|
{
|
||||||
line = line.remove(" \n");
|
line = line.remove(" \n");
|
||||||
line = line.replace("=","");
|
line = line.replace("=","");
|
||||||
@ -117,7 +117,7 @@ void CountryDat::load()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// return country name else ""
|
// return country name else ""
|
||||||
QString CountryDat::find(QString prefix)
|
QString CountryDat::find(QString prefix) const
|
||||||
{
|
{
|
||||||
prefix = prefix.toUpper ();
|
prefix = prefix.toUpper ();
|
||||||
auto pf = prefix;
|
auto pf = prefix;
|
||||||
@ -143,6 +143,3 @@ QString CountryDat::find(QString prefix)
|
|||||||
}
|
}
|
||||||
return QString {};
|
return QString {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,13 +19,13 @@ class CountryDat
|
|||||||
public:
|
public:
|
||||||
void init(const QString filename);
|
void init(const QString filename);
|
||||||
void load();
|
void load();
|
||||||
QString find(QString prefix); // return country name or ""
|
QString find(QString prefix) const; // return country name or ""
|
||||||
QStringList getCountryNames() { return _countryNames; };
|
QStringList getCountryNames() const { return _countryNames; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _extractName(const QString line);
|
QString _extractName(const QString line) const;
|
||||||
void _removeBrackets(QString &line, const QString a, const QString b);
|
void _removeBrackets(QString &line, const QString a, const QString b) const;
|
||||||
QStringList _extractPrefix(QString &line, bool &more);
|
QStringList _extractPrefix(QString &line, bool &more) const;
|
||||||
|
|
||||||
QString _filename;
|
QString _filename;
|
||||||
QStringList _countryNames;
|
QStringList _countryNames;
|
||||||
|
@ -67,7 +67,7 @@ void LogBook::_setAlreadyWorkedFromLog()
|
|||||||
void LogBook::match(/*in*/const QString call,
|
void LogBook::match(/*in*/const QString call,
|
||||||
/*out*/ QString &countryName,
|
/*out*/ QString &countryName,
|
||||||
bool &callWorkedBefore,
|
bool &callWorkedBefore,
|
||||||
bool &countryWorkedBefore)
|
bool &countryWorkedBefore) const
|
||||||
{
|
{
|
||||||
if (call.length() > 0)
|
if (call.length() > 0)
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ public:
|
|||||||
void match(/*in*/ const QString call,
|
void match(/*in*/ const QString call,
|
||||||
/*out*/ QString &countryName,
|
/*out*/ QString &countryName,
|
||||||
bool &callWorkedBefore,
|
bool &callWorkedBefore,
|
||||||
bool &countryWorkedBefore);
|
bool &countryWorkedBefore) const;
|
||||||
void addAsWorked(const QString call, const QString band, const QString mode, const QString date);
|
void addAsWorked(const QString call, const QString band, const QString mode, const QString date);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
159
mainwindow.cpp
159
mainwindow.cpp
@ -42,6 +42,7 @@
|
|||||||
#include "widegraph.h"
|
#include "widegraph.h"
|
||||||
#include "sleep.h"
|
#include "sleep.h"
|
||||||
#include "logqso.h"
|
#include "logqso.h"
|
||||||
|
#include "decodedtext.h"
|
||||||
#include "Radio.hpp"
|
#include "Radio.hpp"
|
||||||
#include "Bands.hpp"
|
#include "Bands.hpp"
|
||||||
#include "TransceiverFactory.hpp"
|
#include "TransceiverFactory.hpp"
|
||||||
@ -690,7 +691,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
|||||||
connect(m_wideGraph.data (), SIGNAL(setFreq3(int,int)),this,
|
connect(m_wideGraph.data (), SIGNAL(setFreq3(int,int)),this,
|
||||||
SLOT(setFreq4(int,int)));
|
SLOT(setFreq4(int,int)));
|
||||||
|
|
||||||
m_QSOText.clear();
|
|
||||||
decodeBusy(false);
|
decodeBusy(false);
|
||||||
QString t1[28]={"1 uW","2 uW","5 uW","10 uW","20 uW","50 uW","100 uW","200 uW","500 uW",
|
QString t1[28]={"1 uW","2 uW","5 uW","10 uW","20 uW","50 uW","100 uW","200 uW","500 uW",
|
||||||
"1 mW","2 mW","5 mW","10 mW","20 mW","50 mW","100 mW","200 mW","500 mW",
|
"1 mW","2 mW","5 mW","10 mW","20 mW","50 mW","100 mW","200 mW","500 mW",
|
||||||
@ -856,6 +856,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
|||||||
m_bDoubleClicked=false;
|
m_bDoubleClicked=false;
|
||||||
m_bCallingCQ=false;
|
m_bCallingCQ=false;
|
||||||
m_wait=0;
|
m_wait=0;
|
||||||
|
m_CQtype="CQ";
|
||||||
|
|
||||||
if(m_mode.startsWith ("WSPR") and m_pctx>0) {
|
if(m_mode.startsWith ("WSPR") and m_pctx>0) {
|
||||||
QPalette palette {ui->sbTxPercent->palette ()};
|
QPalette palette {ui->sbTxPercent->palette ()};
|
||||||
@ -1190,8 +1191,7 @@ void MainWindow::dataSink(qint64 frames)
|
|||||||
int ftol = ui->sbFtol->value ();
|
int ftol = ui->sbFtol->value ();
|
||||||
freqcal_(&dec_data.d2[0],&k,&nkhz,&RxFreq,&ftol,&line[0],80);
|
freqcal_(&dec_data.d2[0],&k,&nkhz,&RxFreq,&ftol,&line[0],80);
|
||||||
QString t=QString::fromLatin1(line);
|
QString t=QString::fromLatin1(line);
|
||||||
DecodedText decodedtext;
|
DecodedText decodedtext {t};
|
||||||
decodedtext=t;
|
|
||||||
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.DXCC(),
|
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.DXCC(),
|
||||||
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
|
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
|
||||||
m_config.color_NewCall());
|
m_config.color_NewCall());
|
||||||
@ -1425,10 +1425,8 @@ void MainWindow::fastSink(qint64 frames)
|
|||||||
m_fastGraph->plotSpec(m_diskData,m_UTCdisk);
|
m_fastGraph->plotSpec(m_diskData,m_UTCdisk);
|
||||||
|
|
||||||
if(bmsk144 and (line[0]!=0)) {
|
if(bmsk144 and (line[0]!=0)) {
|
||||||
DecodedText decodedtext;
|
QString message {QString::fromLatin1 (line)};
|
||||||
QString message;
|
DecodedText decodedtext {message.replace (QChar::LineFeed, "")};
|
||||||
message=QString::fromLatin1(line);
|
|
||||||
decodedtext=message.replace(QChar::LineFeed,"");
|
|
||||||
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.DXCC(),
|
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.DXCC(),
|
||||||
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
|
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
|
||||||
m_config.color_NewCall());
|
m_config.color_NewCall());
|
||||||
@ -1438,7 +1436,7 @@ void MainWindow::fastSink(qint64 frames)
|
|||||||
writeAllTxt(message);
|
writeAllTxt(message);
|
||||||
bool stdMsg = decodedtext.report(m_baseCall,
|
bool stdMsg = decodedtext.report(m_baseCall,
|
||||||
Radio::base_callsign(ui->dxCallEntry->text()),m_rptRcvd);
|
Radio::base_callsign(ui->dxCallEntry->text()),m_rptRcvd);
|
||||||
decodedtext=message.mid(0,4) + message.mid(6,-1);
|
decodedtext = DecodedText {message.left (4) + message.mid (6, -1)};
|
||||||
if (stdMsg) pskPost (decodedtext);
|
if (stdMsg) pskPost (decodedtext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2569,8 +2567,7 @@ void::MainWindow::fast_decode_done()
|
|||||||
if(narg[13]/8==narg[12]) message=message.trimmed().replace("<...>",m_calls);
|
if(narg[13]/8==narg[12]) message=message.trimmed().replace("<...>",m_calls);
|
||||||
|
|
||||||
//Left (Band activity) window
|
//Left (Band activity) window
|
||||||
DecodedText decodedtext;
|
DecodedText decodedtext {message.replace (QChar::LineFeed, "")};
|
||||||
decodedtext=message.replace(QChar::LineFeed,"");
|
|
||||||
if(!m_bFastDone) {
|
if(!m_bFastDone) {
|
||||||
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.DXCC(),
|
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.DXCC(),
|
||||||
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
|
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
|
||||||
@ -2589,12 +2586,12 @@ void::MainWindow::fast_decode_done()
|
|||||||
if(m_mode=="JT9" or m_mode=="MSK144") {
|
if(m_mode=="JT9" or m_mode=="MSK144") {
|
||||||
// find and extract any report for myCall
|
// find and extract any report for myCall
|
||||||
QString msg=message.mid(0,4) + message.mid(6,-1);
|
QString msg=message.mid(0,4) + message.mid(6,-1);
|
||||||
decodedtext=msg.replace(QChar::LineFeed,"");
|
decodedtext = DecodedText {msg.replace (QChar::LineFeed, "")};
|
||||||
bool stdMsg = decodedtext.report(m_baseCall,
|
bool stdMsg = decodedtext.report(m_baseCall,
|
||||||
Radio::base_callsign(ui->dxCallEntry->text()), m_rptRcvd);
|
Radio::base_callsign(ui->dxCallEntry->text()), m_rptRcvd);
|
||||||
|
|
||||||
// extract details and send to PSKreporter
|
// extract details and send to PSKreporter
|
||||||
if (stdMsg) pskPost(decodedtext);
|
if (stdMsg) pskPost (decodedtext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_startAnother=m_loopall;
|
m_startAnother=m_loopall;
|
||||||
@ -2706,21 +2703,20 @@ void MainWindow::readFromStdout() //readFromStdout
|
|||||||
.arg (f.fileName ()).arg (f.errorString ()));
|
.arg (f.fileName ()).arg (f.errorString ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_config.insert_blank () && m_blankLine)
|
if (m_config.insert_blank () && m_blankLine)
|
||||||
{
|
{
|
||||||
QString band;
|
QString band;
|
||||||
if (QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged > 50)
|
if (QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged > 50)
|
||||||
{
|
{
|
||||||
band = ' ' + m_config.bands ()->find (m_freqNominal);
|
band = ' ' + m_config.bands ()->find (m_freqNominal);
|
||||||
}
|
}
|
||||||
ui->decodedTextBrowser->insertLineSpacer (band.rightJustified (40, '-'));
|
ui->decodedTextBrowser->insertLineSpacer (band.rightJustified (40, '-'));
|
||||||
m_blankLine = false;
|
m_blankLine = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodedText decodedtext;
|
DecodedText decodedtext {QString::fromUtf8 (t.constData ()).remove (QRegularExpression {"\r|\n"})};
|
||||||
decodedtext = QString::fromUtf8 (t.constData ()).remove (QRegularExpression {"\r|\n"});
|
|
||||||
|
|
||||||
//Left (Band activity) window
|
//Left (Band activity) window
|
||||||
if(!bAvgMsg) {
|
if(!bAvgMsg) {
|
||||||
ui->decodedTextBrowser->displayDecodedText(decodedtext,m_baseCall,m_config.DXCC(),
|
ui->decodedTextBrowser->displayDecodedText(decodedtext,m_baseCall,m_config.DXCC(),
|
||||||
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),
|
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),
|
||||||
@ -2761,7 +2757,7 @@ void MainWindow::readFromStdout() //readFromStdout
|
|||||||
if(b65 and m_modeTx!="JT65") on_pbTxMode_clicked();
|
if(b65 and m_modeTx!="JT65") on_pbTxMode_clicked();
|
||||||
if(!b65 and m_modeTx=="JT65") on_pbTxMode_clicked();
|
if(!b65 and m_modeTx=="JT65") on_pbTxMode_clicked();
|
||||||
}
|
}
|
||||||
m_QSOText=decodedtext;
|
m_QSOText = decodedtext.string ();
|
||||||
}
|
}
|
||||||
if(m_mode=="FT8" or m_mode=="QRA64") auto_sequence (decodedtext.string(), 25, 50);
|
if(m_mode=="FT8" or m_mode=="QRA64") auto_sequence (decodedtext.string(), 25, 50);
|
||||||
|
|
||||||
@ -2835,7 +2831,7 @@ void MainWindow::auto_sequence (QString const& message, unsigned start_tolerance
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::pskPost (DecodedText decodedtext)
|
void MainWindow::pskPost (DecodedText const& decodedtext)
|
||||||
{
|
{
|
||||||
if (m_diskData || !m_config.spot_to_psk_reporter() || decodedtext.isLowConfidence ()) return;
|
if (m_diskData || !m_config.spot_to_psk_reporter() || decodedtext.isLowConfidence ()) return;
|
||||||
|
|
||||||
@ -3647,7 +3643,6 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
|||||||
{
|
{
|
||||||
QString t1 = messages.left(position); //contents up to \n on selected line
|
QString t1 = messages.left(position); //contents up to \n on selected line
|
||||||
int i1=t1.lastIndexOf(QChar::LineFeed) + 1; //points to first char of line
|
int i1=t1.lastIndexOf(QChar::LineFeed) + 1; //points to first char of line
|
||||||
DecodedText decodedtext;
|
|
||||||
QString t2 = messages.mid(i1,position-i1); //selected line
|
QString t2 = messages.mid(i1,position-i1); //selected line
|
||||||
|
|
||||||
// basic mode sanity checks
|
// basic mode sanity checks
|
||||||
@ -3686,15 +3681,8 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
decodedtext = t2a;
|
DecodedText decodedtext {t2a};
|
||||||
|
decodedtext.removeAddedInfo ();
|
||||||
if (decodedtext.indexOf(" CQ ") > 0) {
|
|
||||||
// TODO this magic 37 characters is also referenced in DisplayText::_appendDXCCWorkedB4()
|
|
||||||
auto eom_pos = decodedtext.string ().indexOf (' ', 36);
|
|
||||||
if (eom_pos < 36) eom_pos = decodedtext.string ().size () - 1; // we always want at least the characters
|
|
||||||
// to position 36
|
|
||||||
decodedtext = decodedtext.string ().left (eom_pos + 1); // remove DXCC entity and worked B4 status. TODO need a better way to do this
|
|
||||||
}
|
|
||||||
|
|
||||||
auto t3 = decodedtext.string ();
|
auto t3 = decodedtext.string ();
|
||||||
auto t4 = t3.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").split (" ", QString::SkipEmptyParts);
|
auto t4 = t3.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").split (" ", QString::SkipEmptyParts);
|
||||||
@ -3719,13 +3707,24 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
|||||||
QString hiscall;
|
QString hiscall;
|
||||||
QString hisgrid;
|
QString hisgrid;
|
||||||
decodedtext.deCallAndGrid(/*out*/hiscall,hisgrid);
|
decodedtext.deCallAndGrid(/*out*/hiscall,hisgrid);
|
||||||
if (!Radio::is_callsign (hiscall) // not interested if not from QSO partner
|
bool is_73 = t4.filter (QRegularExpression {"^(73|RR73)$"}).size ();
|
||||||
&& !(t4.size () == 7 // unless it is of the form
|
auto acceptable_73 =
|
||||||
&& (t4.at (5) == m_baseCall // "<our-call> 73"
|
m_QSOProgress >= ROGER_REPORT
|
||||||
|| t4.at (5).startsWith (m_baseCall + '/')
|
&& is_73
|
||||||
|| t4.at (5).endsWith ('/' + m_baseCall))
|
&& ((decodedtext.isStandardMessage ()
|
||||||
&& t4.at (6) == "73")
|
&& (t4.contains (m_baseCall)
|
||||||
&& !(m_QSOProgress >= ROGER_REPORT && message_is_73 (0, t4)))
|
|| t4.contains (m_config.my_callsign ())
|
||||||
|
|| t4.contains (ui->dxCallEntry->text ())
|
||||||
|
|| t4.contains (Radio::base_callsign (ui->dxCallEntry->text ()))
|
||||||
|
|| t4.contains ("DE")))
|
||||||
|
|| !decodedtext.isStandardMessage ());
|
||||||
|
if ((is_73 && !acceptable_73)
|
||||||
|
|| (!Radio::is_callsign (hiscall) // not interested if not from QSO partner
|
||||||
|
&& !(t4.size () == 7 // unless it is of the form
|
||||||
|
&& (t4.at (5) == m_baseCall // "<our-call> 73"
|
||||||
|
|| t4.at (5).startsWith (m_baseCall + '/')
|
||||||
|
|| t4.at (5).endsWith ('/' + m_baseCall))
|
||||||
|
&& t4.at (6) == "73")))
|
||||||
{
|
{
|
||||||
qDebug () << "Not processing message - hiscall:" << hiscall << "hisgrid:" << hisgrid;
|
qDebug () << "Not processing message - hiscall:" << hiscall << "hisgrid:" << hisgrid;
|
||||||
return;
|
return;
|
||||||
@ -3795,8 +3794,8 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
|||||||
}
|
}
|
||||||
m_QSOProgress = SIGNOFF;
|
m_QSOProgress = SIGNOFF;
|
||||||
} else if((m_QSOProgress >= REPORT
|
} else if((m_QSOProgress >= REPORT
|
||||||
|| (m_QSOProgress >= REPLYING && "MSK144" == m_mode && m_config.contestMode ()))
|
|| (m_QSOProgress >= REPLYING && (m_mode=="MSK144" or m_mode=="FT8")
|
||||||
&& r.mid(0,1)=="R") {
|
&& m_config.contestMode ())) && r.mid(0,1)=="R") {
|
||||||
m_ntx=4;
|
m_ntx=4;
|
||||||
m_QSOProgress = ROGERS;
|
m_QSOProgress = ROGERS;
|
||||||
ui->txrb4->setChecked(true);
|
ui->txrb4->setChecked(true);
|
||||||
@ -3835,8 +3834,8 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
|||||||
}
|
}
|
||||||
else if (!(m_bAutoReply && m_QSOProgress > CALLING)) {
|
else if (!(m_bAutoReply && m_QSOProgress > CALLING)) {
|
||||||
if ((t4.size () >= 9 && t4.at (5).contains (m_baseCall) && t4.at (8) == "OOO")
|
if ((t4.size () >= 9 && t4.at (5).contains (m_baseCall) && t4.at (8) == "OOO")
|
||||||
|| (m_mode=="MSK144" && m_config.contestMode())) {
|
|| ((m_mode=="MSK144" or m_mode=="FT8") && m_config.contestMode())) {
|
||||||
// EME short code report or MSK144 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;
|
||||||
ui->txrb3->setChecked (true);
|
ui->txrb3->setChecked (true);
|
||||||
@ -3899,7 +3898,7 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_QSOProgress >= ROGERS && message_is_73 (0, t4)) {
|
else if (acceptable_73) {
|
||||||
if(ui->tabWidget->currentIndex()==1) {
|
if(ui->tabWidget->currentIndex()==1) {
|
||||||
gen_msg = 5;
|
gen_msg = 5;
|
||||||
if (ui->rbGenMsg->isChecked ()) m_ntx=7;
|
if (ui->rbGenMsg->isChecked ()) m_ntx=7;
|
||||||
@ -3932,14 +3931,14 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
|||||||
|
|
||||||
// if we get here then we are reacting to the message
|
// if we get here then we are reacting to the message
|
||||||
if (m_bAutoReply) m_bCallingCQ = CALLING == m_QSOProgress;
|
if (m_bAutoReply) m_bCallingCQ = CALLING == m_QSOProgress;
|
||||||
QString s1=m_QSOText.string().trimmed();
|
QString s1 = m_QSOText.trimmed ();
|
||||||
QString s2=t2.trimmed();
|
QString s2=t2.trimmed();
|
||||||
if (s1!=s2 and !decodedtext.isTX()) {
|
if (s1!=s2 and !decodedtext.isTX()) {
|
||||||
decodedtext=t2;
|
decodedtext = DecodedText {t2};
|
||||||
ui->decodedTextBrowser2->displayDecodedText(decodedtext, m_baseCall,
|
ui->decodedTextBrowser2->displayDecodedText(decodedtext, m_baseCall,
|
||||||
false, m_logBook,m_config.color_CQ(), m_config.color_MyCall(),
|
false, m_logBook,m_config.color_CQ(), m_config.color_MyCall(),
|
||||||
m_config.color_DXCC(),m_config.color_NewCall());
|
m_config.color_DXCC(),m_config.color_NewCall());
|
||||||
m_QSOText=decodedtext;
|
m_QSOText = decodedtext.string ();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hiscall != "73"
|
if (hiscall != "73"
|
||||||
@ -4000,34 +3999,27 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
|||||||
|
|
||||||
void MainWindow::genCQMsg ()
|
void MainWindow::genCQMsg ()
|
||||||
{
|
{
|
||||||
if(m_config.my_callsign().size () && m_config.my_grid().size ())
|
if(m_config.my_callsign().size () && m_config.my_grid().size ()) {
|
||||||
{
|
auto const& grid = m_config.my_callsign () != m_baseCall && shortList (m_config.my_callsign ()) ? QString {} : m_config.my_grid ();
|
||||||
auto const& grid = m_config.my_callsign () != m_baseCall && shortList (m_config.my_callsign ()) ? QString {} : m_config.my_grid ();
|
if (ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked ()) {
|
||||||
if (ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked ())
|
msgtype (QString {"CQ %1 %2 %3"}
|
||||||
{
|
.arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'})
|
||||||
msgtype (QString {"CQ %1 %2 %3"}
|
.arg (m_config.my_callsign())
|
||||||
.arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'})
|
.arg (grid.left (4)),
|
||||||
.arg (m_config.my_callsign())
|
ui->tx6);
|
||||||
.arg (grid.left (4)),
|
} else {
|
||||||
ui->tx6);
|
msgtype (QString {"%1 %2 %3"}.arg(m_CQtype).arg(m_config.my_callsign()).arg(grid.left(4)),ui->tx6);
|
||||||
}
|
}
|
||||||
else
|
if ((m_mode=="JT4" or m_mode=="QRA64") and ui->cbShMsgs->isChecked()) {
|
||||||
{
|
if (ui->cbTx6->isChecked ()) {
|
||||||
msgtype (QString {"CQ %1 %2"}.arg (m_config.my_callsign ()).arg (grid.left (4)), ui->tx6);
|
msgtype ("@1250 (SEND MSGS)", ui->tx6);
|
||||||
}
|
} else {
|
||||||
if ((m_mode=="JT4" or m_mode=="QRA64") and ui->cbShMsgs->isChecked()) {
|
msgtype ("@1000 (TUNE)", ui->tx6);
|
||||||
if (ui->cbTx6->isChecked ()) {
|
|
||||||
msgtype ("@1250 (SEND MSGS)", ui->tx6);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
msgtype ("@1000 (TUNE)", ui->tx6);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
} else {
|
||||||
{
|
ui->tx6->clear ();
|
||||||
ui->tx6->clear ();
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::genStdMsgs(QString rpt, bool unconditional)
|
void MainWindow::genStdMsgs(QString rpt, bool unconditional)
|
||||||
@ -4189,6 +4181,10 @@ void MainWindow::TxAgain()
|
|||||||
|
|
||||||
void MainWindow::clearDX ()
|
void MainWindow::clearDX ()
|
||||||
{
|
{
|
||||||
|
if (m_QSOProgress != CALLING)
|
||||||
|
{
|
||||||
|
auto_tx_mode (false);
|
||||||
|
}
|
||||||
ui->dxCallEntry->clear ();
|
ui->dxCallEntry->clear ();
|
||||||
ui->dxGridEntry->clear ();
|
ui->dxGridEntry->clear ();
|
||||||
m_lastCallsign.clear ();
|
m_lastCallsign.clear ();
|
||||||
@ -4405,7 +4401,10 @@ void MainWindow::on_tx5_currentTextChanged (QString const& text) //tx5 edited
|
|||||||
|
|
||||||
void MainWindow::on_tx6_editingFinished() //tx6 edited
|
void MainWindow::on_tx6_editingFinished() //tx6 edited
|
||||||
{
|
{
|
||||||
QString t=ui->tx6->text();
|
QString t=ui->tx6->text().toUpper();
|
||||||
|
QString t1=t.split(" ").at(1);
|
||||||
|
m_CQtype="CQ";
|
||||||
|
if(t1.size()==2) m_CQtype="CQ " + t1;
|
||||||
msgtype(t, ui->tx6);
|
msgtype(t, ui->tx6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include "DisplayManual.hpp"
|
#include "DisplayManual.hpp"
|
||||||
#include "psk_reporter.h"
|
#include "psk_reporter.h"
|
||||||
#include "logbook/logbook.h"
|
#include "logbook/logbook.h"
|
||||||
#include "decodedtext.h"
|
|
||||||
#include "commons.h"
|
#include "commons.h"
|
||||||
#include "astro.h"
|
#include "astro.h"
|
||||||
#include "MessageBox.hpp"
|
#include "MessageBox.hpp"
|
||||||
@ -82,6 +81,7 @@ class Detector;
|
|||||||
class SampleDownloader;
|
class SampleDownloader;
|
||||||
class MultiSettings;
|
class MultiSettings;
|
||||||
class EqualizationToolsDialog;
|
class EqualizationToolsDialog;
|
||||||
|
class DecodedText;
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
@ -532,6 +532,7 @@ private:
|
|||||||
QString m_msgSent0;
|
QString m_msgSent0;
|
||||||
QString m_fileToSave;
|
QString m_fileToSave;
|
||||||
QString m_calls;
|
QString m_calls;
|
||||||
|
QString m_CQtype;
|
||||||
|
|
||||||
QSet<QString> m_pfx;
|
QSet<QString> m_pfx;
|
||||||
QSet<QString> m_sfx;
|
QSet<QString> m_sfx;
|
||||||
@ -540,7 +541,7 @@ private:
|
|||||||
|
|
||||||
QSharedMemory *mem_jt9;
|
QSharedMemory *mem_jt9;
|
||||||
LogBook m_logBook;
|
LogBook m_logBook;
|
||||||
DecodedText m_QSOText;
|
QString m_QSOText;
|
||||||
unsigned m_msAudioOutputBuffered;
|
unsigned m_msAudioOutputBuffered;
|
||||||
unsigned m_framesAudioInputBuffered;
|
unsigned m_framesAudioInputBuffered;
|
||||||
unsigned m_downSampleFactor;
|
unsigned m_downSampleFactor;
|
||||||
@ -587,7 +588,7 @@ private:
|
|||||||
void transmit (double snr = 99.);
|
void transmit (double snr = 99.);
|
||||||
void rigFailure (QString const& reason);
|
void rigFailure (QString const& reason);
|
||||||
void pskSetLocal ();
|
void pskSetLocal ();
|
||||||
void pskPost(DecodedText decodedtext);
|
void pskPost(DecodedText const& decodedtext);
|
||||||
void displayDialFrequency ();
|
void displayDialFrequency ();
|
||||||
void transmitDisplay (bool);
|
void transmitDisplay (bool);
|
||||||
void processMessage(QString const& messages, qint32 position, bool ctrl = false, bool alt = false);
|
void processMessage(QString const& messages, qint32 position, bool ctrl = false, bool alt = false);
|
||||||
|
@ -18,10 +18,10 @@
|
|||||||
locator to Dx Grid; change Rx and Tx frequencies to<br/>
|
locator to Dx Grid; change Rx and Tx frequencies to<br/>
|
||||||
decoded signal's frequency; generate standard messages.<br/>
|
decoded signal's frequency; generate standard messages.<br/>
|
||||||
If first callsign is your own, Tx frequency is not<br/>
|
If first callsign is your own, Tx frequency is not<br/>
|
||||||
changed unless Ctrl is held down when double-clicking.<br/>
|
changed unless <b>Ctrl</b> is held down when double-clicking.<br/>
|
||||||
<br/>
|
<br/>
|
||||||
Hold down Alt to only move the Rx frequency when<br/>
|
<b>Alt-Double-click</b> to move only Rx frequency when<br/>
|
||||||
double-clicking to reply to a CQ or QRZ caller.
|
replying to a CQ or QRZ caller.
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user