mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2025-08-25 00:42:38 -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/azdist.f90
|
||||
lib/badmsg.f90
|
||||
lib/fsk4hf/baseline.f90
|
||||
lib/bpdecode40.f90
|
||||
lib/bpdecode144.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>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>FT8 and MSK144 Contest Mode</string>
|
||||
<string>FT8 and MSK144: NA VHF Contest Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -2634,12 +2634,12 @@ soundcard changes</string>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="CAT_data_bits_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="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>
|
||||
</ui>
|
||||
|
133
decodedtext.cpp
133
decodedtext.cpp
@ -7,48 +7,79 @@ extern "C" {
|
||||
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})?)"};
|
||||
return callsign_re.match (_string).captured ("callsign");
|
||||
if (message_.length() >= 1)
|
||||
{
|
||||
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?
|
||||
}
|
||||
|
||||
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;
|
||||
return _string.mid(i1,3).toInt();
|
||||
int i1=string_.indexOf(" ")+1;
|
||||
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
|
||||
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(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
|
||||
if (message_.size () < 1) return false;
|
||||
|
||||
QStringList w=msg.split(" ",QString::SkipEmptyParts);
|
||||
if(w.size ()
|
||||
&& b && (w[0] == myBaseCall
|
||||
|| w[0].endsWith ("/" + myBaseCall)
|
||||
|| w[0].startsWith (myBaseCall + "/")
|
||||
|| (w.size () > 1 && !dxBaseCall.isEmpty ()
|
||||
&& (w[1] == dxBaseCall
|
||||
|| w[1].endsWith ("/" + dxBaseCall)
|
||||
|| w[1].startsWith (dxBaseCall + "/")))))
|
||||
QStringList const& w = message_.split(" ",QString::SkipEmptyParts);
|
||||
if (w.size ()
|
||||
&& is_standard_ && (w[0] == myBaseCall
|
||||
|| w[0].endsWith ("/" + myBaseCall)
|
||||
|| w[0].startsWith (myBaseCall + "/")
|
||||
|| (w.size () > 1 && !dxBaseCall.isEmpty ()
|
||||
&& (w[1] == dxBaseCall
|
||||
|| w[1].endsWith ("/" + dxBaseCall)
|
||||
|| w[1].startsWith (dxBaseCall + "/")))))
|
||||
{
|
||||
QString tt="";
|
||||
if(w.size() > 2) tt=w[2];
|
||||
bool ok;
|
||||
i1=tt.toInt(&ok);
|
||||
if (ok and i1>=-50 and i1<50)
|
||||
QString tt="";
|
||||
if(w.size() > 2) tt=w[2];
|
||||
bool ok;
|
||||
auto i1=tt.toInt(&ok);
|
||||
if (ok and i1>=-50 and i1<50)
|
||||
{
|
||||
report = tt;
|
||||
report = tt;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (tt.mid(0,1)=="R")
|
||||
if (tt.mid(0,1)=="R")
|
||||
{
|
||||
i1=tt.mid(1).toInt(&ok);
|
||||
if(ok and i1>=-50 and i1<50)
|
||||
i1=tt.mid(1).toInt(&ok);
|
||||
if(ok and i1>=-50 and i1<50)
|
||||
{
|
||||
report = tt.mid(1);
|
||||
report = tt.mid(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
return is_standard_;
|
||||
}
|
||||
|
||||
// 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_);
|
||||
int i = call.indexOf(" ");
|
||||
return call.mid(0,i);
|
||||
}
|
||||
|
||||
// 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
|
||||
msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
|
||||
int i1 = msg.indexOf (" ");
|
||||
@ -133,9 +158,9 @@ void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid)
|
||||
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
|
||||
*/
|
||||
|
||||
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();
|
||||
if (sr<-50)
|
||||
|
@ -27,54 +27,41 @@
|
||||
class DecodedText
|
||||
{
|
||||
public:
|
||||
void operator=(const QString &rhs)
|
||||
{
|
||||
_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
|
||||
};
|
||||
explicit DecodedText (QString const&);
|
||||
|
||||
void operator+=(const QString &rhs)
|
||||
{
|
||||
_string += rhs;
|
||||
};
|
||||
QString string() const { return string_; };
|
||||
void removeAddedInfo ();
|
||||
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); };
|
||||
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); };
|
||||
QString CQersCall() const;
|
||||
|
||||
void clear() { _string.clear(); };
|
||||
|
||||
QString CQersCall();
|
||||
|
||||
bool isJT65();
|
||||
bool isJT9();
|
||||
bool isTX();
|
||||
bool isLowConfidence ();
|
||||
int frequencyOffset(); // hertz offset from the tuned dial or rx frequency, aka audio frequency
|
||||
int snr();
|
||||
float dt();
|
||||
bool isJT65() const;
|
||||
bool isJT9() const;
|
||||
bool isTX() const;
|
||||
bool isStandardMessage () const {return is_standard_;}
|
||||
bool isLowConfidence () const;
|
||||
int frequencyOffset() const; // hertz offset from the tuned dial or rx frequency, aka audio frequency
|
||||
int snr() const;
|
||||
float dt() const;
|
||||
|
||||
// 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
|
||||
QString call();
|
||||
QString call() const;
|
||||
|
||||
// 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
|
||||
QString report();
|
||||
QString report() const;
|
||||
|
||||
private:
|
||||
// These define the columns in the decoded text where fields are to be found.
|
||||
@ -86,8 +73,10 @@ private:
|
||||
column_mode = 19,
|
||||
column_qsoText = 22 };
|
||||
|
||||
QString _string;
|
||||
QString string_;
|
||||
int padding_;
|
||||
QString message_;
|
||||
bool is_standard_;
|
||||
};
|
||||
|
||||
#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,
|
||||
LogBook logBook, QColor color_CQ,
|
||||
LogBook const& logBook, QColor color_CQ,
|
||||
QColor color_DXCC,
|
||||
QColor color_NewCall)
|
||||
{
|
||||
@ -158,8 +158,8 @@ QString DisplayText::appendDXCCWorkedB4(QString message, QString const& callsign
|
||||
return message;
|
||||
}
|
||||
|
||||
void DisplayText::displayDecodedText(DecodedText decodedText, QString myCall,
|
||||
bool displayDXCCEntity, LogBook logBook,
|
||||
void DisplayText::displayDecodedText(DecodedText const& decodedText, QString const& myCall,
|
||||
bool displayDXCCEntity, LogBook const& logBook,
|
||||
QColor color_CQ, QColor color_MyCall,
|
||||
QColor color_DXCC, QColor color_NewCall)
|
||||
{
|
||||
|
@ -17,8 +17,8 @@ public:
|
||||
|
||||
void setContentFont (QFont const&);
|
||||
void insertLineSpacer(QString const&);
|
||||
void displayDecodedText(DecodedText decodedText, QString myCall, bool displayDXCCEntity,
|
||||
LogBook logBook, QColor color_CQ, QColor color_MyCall,
|
||||
void displayDecodedText(DecodedText const& decodedText, QString const& myCall, bool displayDXCCEntity,
|
||||
LogBook const& logBook, QColor color_CQ, QColor color_MyCall,
|
||||
QColor color_DXCC, QColor color_NewCall);
|
||||
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
||||
QColor color_TxMsg, bool bFastMode);
|
||||
@ -32,7 +32,7 @@ protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
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
|
||||
and FT8 can use these AP bits to decode messages containing them with
|
||||
higher sensitivity than otherwise possible.
|
||||
and FT8 can use these and similar AP bits to decode messages
|
||||
containing them with higher sensitivity than otherwise possible.
|
||||
|
||||
We have implemented AP decoding in slightly different ways in QRA64
|
||||
and FT8. To provide some explicit examples for users, we provide here
|
||||
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
|
||||
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
|
||||
are consistent with the hypothesized AP bits. If a codeword is found
|
||||
that the decoder judges to have high (but not overwhelmingly high)
|
||||
probability of being correct, a ? character is appended when the
|
||||
decoded message is displayed. Decodes thus marked are not sent to
|
||||
{pskreporter} to avoid occasional misleading spots of false decodes.
|
||||
decoded message is displayed. To avoid misleading spots of occasional
|
||||
false decodes, messages so marked are not forwarded to {pskreporter}.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
[[AP_INFO_TABLE]]
|
||||
@ -51,6 +43,23 @@ successful decode used MyCall as hypothetically known information.
|
||||
|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
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
slots mentioned above.
|
||||
|
||||
Finally, the message compression algorithm supports messages starting
|
||||
with `CQ AA` through `CQ ZZ`. Such messages are encoded by
|
||||
sending `E9AA` through `E9ZZ` in place of the first callsign of a
|
||||
standard message. Upon reception these calls are converted back to
|
||||
the form `CQ AA` through `CQ ZZ`.
|
||||
As a convenience for sending directed CQ messages, the compression
|
||||
algorithm supports messages starting with `CQ AA` through `CQ ZZ`.
|
||||
These message fragments are encoded internally as if they were the
|
||||
callsigns `E9AA` through `E9ZZ`. Upon reception they are converted
|
||||
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
|
||||
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
|
||||
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
|
||||
partners have exchanged both callsigns. Short messages consist of 4
|
||||
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
|
||||
testing to make sure that sequencing is correct.
|
||||
|
||||
- Check *FT8 and MSK144 Contest Mode* to enable generation and
|
||||
auto-sequencing of MSK144 messages with four-character grid locators
|
||||
in place of signal reports.
|
||||
- Check *FT8 and MSK144: NA VHF Contest Mode* to enable generation and
|
||||
auto-sequencing of messages using four-character grid locators in
|
||||
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
|
||||
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
|
||||
being readable by anyone listening in.
|
||||
|
||||
- A special *Contest Mode* for MSK144 can be activated by checking a
|
||||
box on the *Settings | Advanced* tab. This mode is configured
|
||||
especially for VHF contests in which four-character grid locators are
|
||||
the required exchange. When *Contest Mode* is active, the standard QSO
|
||||
sequence looks like this:
|
||||
- A special *VHF Contest Mode* for FT8 and MSK144 can be activated by
|
||||
checking a box on the *Settings | Advanced* tab. This mode is
|
||||
configured especially for VHF contests in which four-character grid
|
||||
locators are the required exchange. When *Contest Mode* is active,
|
||||
the standard QSO sequence looks like this:
|
||||
|
||||
CQ K1ABC FN42
|
||||
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
|
||||
|
||||
data nfft0/0/
|
||||
data aclast/1.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 aclast/0.0,0.0,0.0,0.0,0.0/
|
||||
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
|
||||
|
||||
@ -43,8 +45,8 @@ subroutine analytic(d,npts,nfft,c,pc,beq)
|
||||
if( any(aclast .ne. ac) .or. any(pclast .ne. pc) ) then
|
||||
aclast=ac
|
||||
pclast=pc
|
||||
write(*,3001) pc
|
||||
3001 format('Phase coeffs:',5f12.6)
|
||||
! write(*,3001) pc
|
||||
!3001 format('Phase coeffs:',5f12.6)
|
||||
do i=1,nh+1
|
||||
ff=(i-1)*df
|
||||
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, &
|
||||
lsubtract,nagain,iaptype,mygrid6,bcontest,sync0,f1,xdt,apsym,nharderrors,&
|
||||
dmin,nbadcrc,ipass,iera,message,xsnr)
|
||||
lsubtract,nagain,iaptype,mygrid6,bcontest,sync0,f1,xdt,xbase,apsym, &
|
||||
nharderrors,dmin,nbadcrc,ipass,iera,message,xsnr)
|
||||
|
||||
use timer_module, only: timer
|
||||
include 'ft8_params.f90'
|
||||
@ -12,7 +12,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
||||
real a(5)
|
||||
real s1(0:7,ND),s2(0:7,NN)
|
||||
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 dd0(15*12000)
|
||||
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)
|
||||
if( i1.ge.1 .and. i1+31 .le. NP2 ) csymb=cd0(i1:i1+31)
|
||||
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
|
||||
|
||||
! sync quality check
|
||||
@ -146,39 +146,38 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
||||
|
||||
j=0
|
||||
do k=1,NN
|
||||
if(k.le.7) cycle
|
||||
if(k.ge.37 .and. k.le.43) cycle
|
||||
if(k.gt.72) cycle
|
||||
j=j+1
|
||||
s1(0:7,j)=s2(0:7,k)
|
||||
if(k.le.7) cycle
|
||||
if(k.ge.37 .and. k.le.43) cycle
|
||||
if(k.gt.72) cycle
|
||||
j=j+1
|
||||
s1(0:7,j)=s2(0:7,k)
|
||||
enddo
|
||||
|
||||
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
|
||||
i2=3*j-1
|
||||
i1=3*j
|
||||
rxdata(i4)=r4
|
||||
rxdata(i2)=r2
|
||||
rxdata(i1)=r1
|
||||
rxdatap(i4)=r4
|
||||
rxdatap(i2)=r2
|
||||
rxdatap(i1)=r1
|
||||
ps=s1(0:7,j)
|
||||
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))
|
||||
bmeta(i4)=r4
|
||||
bmeta(i2)=r2
|
||||
bmeta(i1)=r1
|
||||
bmetap(i4)=r4
|
||||
bmetap(i2)=r2
|
||||
bmetap(i1)=r1
|
||||
|
||||
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
|
||||
! 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(apsym(28).lt.0) then
|
||||
rxdatap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
|
||||
rxdatap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
|
||||
bmetap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
|
||||
bmetap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
|
||||
else
|
||||
rxdatap(i2)=max(ps(6),ps(7))-max(ps(4),ps(5))
|
||||
rxdatap(i1)=max(ps(5),ps(7))-max(ps(4),ps(6))
|
||||
bmetap(i2)=max(ps(6),ps(7))-max(ps(4),ps(5))
|
||||
bmetap(i1)=max(ps(5),ps(7))-max(ps(4),ps(6))
|
||||
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.
|
||||
! 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
|
||||
! if(iii.eq.0) rxdatap(i4)=ps(4)-ps(0)
|
||||
! if(iii.eq.1) rxdatap(i4)=ps(5)-ps(1)
|
||||
! if(iii.eq.2) rxdatap(i4)=ps(6)-ps(2)
|
||||
! if(iii.eq.3) rxdatap(i4)=ps(7)-ps(3)
|
||||
! if(iii.eq.0) bmetap(i4)=ps(4)-ps(0)
|
||||
! if(iii.eq.1) bmetap(i4)=ps(5)-ps(1)
|
||||
! if(iii.eq.2) bmetap(i4)=ps(6)-ps(2)
|
||||
! if(iii.eq.3) bmetap(i4)=ps(7)-ps(3)
|
||||
! endif
|
||||
|
||||
! 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
|
||||
if(j.eq.48) then ! bit 144 is always 1
|
||||
rxdatap(i4)=max(ps(5),ps(7))-max(ps(1),ps(3))
|
||||
rxdatap(i2)=max(ps(3),ps(7))-max(ps(1),ps(5))
|
||||
bmetap(i4)=max(ps(5),ps(7))-max(ps(1),ps(3))
|
||||
bmetap(i2)=max(ps(3),ps(7))-max(ps(1),ps(5))
|
||||
endif
|
||||
|
||||
! 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
|
||||
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))
|
||||
rxdatap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
|
||||
bmetap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
|
||||
bmetap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
|
||||
endif
|
||||
|
||||
enddo
|
||||
|
||||
rxav=sum(rxdata)/(3.0*ND)
|
||||
rx2av=sum(rxdata*rxdata)/(3.0*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
|
||||
call normalizebmet(bmeta,3*ND)
|
||||
call normalizebmet(bmetap,3*ND)
|
||||
|
||||
ss=0.84
|
||||
llr0=2.0*rxdata/(ss*ss)
|
||||
llra=2.0*rxdatap/(ss*ss) ! llr's for use with ap
|
||||
llr0=2.0*bmeta/(ss*ss)
|
||||
llra=2.0*bmetap/(ss*ss) ! llr's for use with ap
|
||||
apmag=4.0
|
||||
|
||||
! pass #
|
||||
@ -245,11 +235,8 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
||||
do ipass=1,npasses
|
||||
|
||||
llr=llr0
|
||||
if(ipass.ne.2 .and. ipass.ne.3) nblank=0
|
||||
if(ipass.eq.2) nblank=24
|
||||
if(ipass.eq.3) nblank=48
|
||||
if(nblank.gt.0) llr(1:nblank)=0.
|
||||
|
||||
if(ipass.eq.2) llr(1:24)=0.
|
||||
if(ipass.eq.3) llr(1:48)=0.
|
||||
if(ipass.le.3) then
|
||||
apmask=0
|
||||
llrap=llr
|
||||
@ -308,23 +295,24 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
||||
call timer('bpd174 ',1)
|
||||
dmin=0.0
|
||||
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(ipass.le.3 .and. .not.nagain) then
|
||||
norder=2
|
||||
else ! norder=3 for nagain and AP decodes
|
||||
norder=3
|
||||
if((ipass.eq.2 .or. ipass.eq.3) .and. .not.nagain) then
|
||||
ndeep=3
|
||||
else
|
||||
ndeep=4
|
||||
endif
|
||||
endif
|
||||
if(nagain) ndeep=5
|
||||
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)
|
||||
endif
|
||||
nbadcrc=1
|
||||
message=' '
|
||||
xsnr=-99.0
|
||||
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. &
|
||||
.not.(sync.lt.2.0 .and. nharderrors.gt.35) .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
|
||||
if(xnoi.gt.0 .and. xnoi.lt.xsig) xsnr=xsig/xnoi-1.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
|
||||
return
|
||||
endif
|
||||
@ -356,3 +350,18 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
||||
|
||||
return
|
||||
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()
|
||||
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*,'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.'
|
||||
return
|
||||
endif
|
||||
call getarg(1,arg)
|
||||
read(arg,*) max_iterations
|
||||
call getarg(2,arg)
|
||||
read(arg,*) norder
|
||||
read(arg,*) ndepth
|
||||
call getarg(3,arg)
|
||||
read(arg,*) ntrials
|
||||
call getarg(4,arg)
|
||||
@ -128,13 +128,14 @@ allocate ( rxdata(N), llr(N) )
|
||||
|
||||
call encode174(msgbits,codeword)
|
||||
call init_random_seed()
|
||||
call sgran()
|
||||
! call sgran()
|
||||
|
||||
write(*,*) 'codeword'
|
||||
write(*,'(22(8i1,1x))') codeword
|
||||
|
||||
write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma"
|
||||
do idb = 20,-10,-1
|
||||
!do idb = -3,-3,-1
|
||||
db=idb/2.0-1.0
|
||||
sigma=1/sqrt( 2*(10**(db/10.0)) )
|
||||
ngood=0
|
||||
@ -188,8 +189,8 @@ do idb = 20,-10,-1
|
||||
apmask(colorder(174-87+1:174-87+nap)+1)=1
|
||||
|
||||
! max_iterations is max number of belief propagation iterations
|
||||
call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors)
|
||||
if( norder .ge. 0 .and. nharderrors .lt. 0 ) call osd174(llr, norder, decoded, cw, nharderrors)
|
||||
call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors,niterations)
|
||||
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( nharderrors .ge. 0 ) then
|
||||
call extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent)
|
||||
@ -206,7 +207,6 @@ do idb = 20,-10,-1
|
||||
endif
|
||||
enddo
|
||||
nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1
|
||||
|
||||
if( ncrcflag .eq. 1 ) then
|
||||
if( nueflag .eq. 0 ) then
|
||||
ngood=ngood+1
|
||||
@ -217,7 +217,7 @@ do idb = 20,-10,-1
|
||||
endif
|
||||
endif
|
||||
enddo
|
||||
baud=12000/2048
|
||||
baud=12000/1920
|
||||
snr2500=db+10.0*log10((baud/2500.0))
|
||||
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
|
||||
|
@ -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.
|
||||
!
|
||||
@ -7,15 +7,15 @@ include "ldpc_174_87_params.f90"
|
||||
integer*1 apmask(N),apmaskr(N)
|
||||
integer*1 gen(K,N)
|
||||
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*1 cw(N),ce(N),c0(N),hdec(N)
|
||||
integer*1 decoded(K)
|
||||
integer indx(N)
|
||||
real llr(N),rx(N),absrx(N)
|
||||
logical first
|
||||
logical first,reset
|
||||
data first/.true./
|
||||
|
||||
save first,gen
|
||||
|
||||
if( first ) then ! fill the generator matrix
|
||||
@ -35,30 +35,26 @@ if( first ) then ! fill the generator matrix
|
||||
first=.false.
|
||||
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)
|
||||
apmaskr=apmask(colorder+1)
|
||||
|
||||
|
||||
! hard decode the received word
|
||||
! Hard decisions on the received word.
|
||||
hdec=0
|
||||
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)
|
||||
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
|
||||
genmrb(1:K,i)=gen(1:K,indx(N+1-i))
|
||||
indices(i)=indx(N+1-i)
|
||||
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).
|
||||
! 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 icol=id,K+20 ! The 20 is ad hoc - beware
|
||||
iflag=0
|
||||
@ -87,8 +83,8 @@ g2=transpose(genmrb)
|
||||
! 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.
|
||||
! 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
|
||||
! codeword is most likely to be correct.
|
||||
! codewords. Return the member of the list that has the smallest Euclidean
|
||||
! distance to the received word.
|
||||
|
||||
hdec=hdec(indices) ! hard decisions from received symbols
|
||||
m0=hdec(1:K) ! zero'th order message
|
||||
@ -96,55 +92,170 @@ absrx=absrx(indices)
|
||||
rx=rx(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)
|
||||
nxor=ieor(c0,hdec)
|
||||
nhardmin=sum(nxor)
|
||||
dmin=sum(nxor*absrx)
|
||||
thresh=rho*dmin
|
||||
|
||||
cw=c0
|
||||
nt=0
|
||||
ntotal=0
|
||||
nrejected=0
|
||||
do iorder=1,norder
|
||||
mi(1:K-iorder)=0
|
||||
mi(K-iorder+1:K)=1
|
||||
iflag=0
|
||||
do while(iflag .ge. 0 )
|
||||
if(all(iand(apmaskr(1:K),mi).eq.0)) then ! reject patterns with ap bits
|
||||
dpat=sum(mi*absrx(1:K))
|
||||
nt=nt+1
|
||||
if( dpat .lt. thresh ) then ! reject unlikely error patterns
|
||||
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)
|
||||
thresh=rho*dmin
|
||||
endif
|
||||
|
||||
if(ndeep.eq.0) goto 998 ! norder=0
|
||||
if(ndeep.gt.5) ndeep=5
|
||||
if( ndeep.eq. 1) then
|
||||
nord=1
|
||||
npre1=0
|
||||
npre2=0
|
||||
nt=40
|
||||
ntheta=12
|
||||
elseif(ndeep.eq.2) then
|
||||
nord=1
|
||||
npre1=1
|
||||
npre2=0
|
||||
nt=40
|
||||
ntheta=12
|
||||
elseif(ndeep.eq.3) then
|
||||
nord=1
|
||||
npre1=1
|
||||
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
|
||||
nrejected=nrejected+1
|
||||
iend=1
|
||||
endif
|
||||
endif
|
||||
! get the next test error pattern, iflag will go negative
|
||||
! when the last pattern with weight iorder has been generated
|
||||
call nextpat(mi,k,iorder,iflag)
|
||||
enddo
|
||||
do n1=iflag,iend,-1
|
||||
mi=misub
|
||||
mi(n1)=1
|
||||
if(any(iand(apmaskr(1:K),mi).eq.1)) cycle
|
||||
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
|
||||
|
||||
!write(*,*) 'nhardmin ',nhardmin
|
||||
!write(*,*) 'total patterns ',nt,' number rejected ',nrejected
|
||||
if(npre2.eq.1) then
|
||||
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
|
||||
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
|
||||
return
|
||||
end subroutine osd174
|
||||
@ -181,6 +292,86 @@ subroutine nextpat(mi,k,iorder,iflag)
|
||||
ms(k-nz+1:k)=1
|
||||
endif
|
||||
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
|
||||
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'
|
||||
! 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)
|
||||
real s(NH1,NHSYM)
|
||||
real savg(NH1)
|
||||
real sbase(NH1)
|
||||
real x(NFFT1)
|
||||
real sync2d(NH1,-JZ:JZ)
|
||||
real red(NH1)
|
||||
@ -35,7 +36,8 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand)
|
||||
enddo
|
||||
savg=savg + s(1:NH1,j) !Average spectrum
|
||||
enddo
|
||||
savg=savg/NHSYM
|
||||
call baseline(savg,nfa,nfb,sbase)
|
||||
! savg=savg/NHSYM
|
||||
! do i=1,NH1
|
||||
! write(51,3051) i*df,savg(i),db(savg(i))
|
||||
!3051 format(f10.3,e12.3,f12.3)
|
||||
|
@ -34,6 +34,7 @@ contains
|
||||
class(ft8_decoder), intent(inout) :: this
|
||||
procedure(ft8_decode_callback) :: callback
|
||||
real s(NH1,NHSYM)
|
||||
real sbase(NH1)
|
||||
real candidate(3,200)
|
||||
real dd(15*12000)
|
||||
logical, intent(in) :: lapon,nagain
|
||||
@ -67,63 +68,62 @@ contains
|
||||
! For now:
|
||||
! ndepth=1: no subtraction, 1 pass, 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.ge.2) npass=2
|
||||
if(ndepth.ge.2) npass=3
|
||||
do ipass=1,npass
|
||||
newdat=.true. ! Is this a problem? I hijacked newdat.
|
||||
syncmin=1.5
|
||||
if(ipass.eq.1) then
|
||||
lsubtract=.true.
|
||||
if(ndepth.eq.1) lsubtract=.false.
|
||||
syncmin=1.5
|
||||
else
|
||||
lsubtract=.false.
|
||||
syncmin=1.5
|
||||
elseif(ipass.eq.2) then
|
||||
n2=ndecodes
|
||||
if(ndecodes.eq.0) cycle
|
||||
lsubtract=.true.
|
||||
elseif(ipass.eq.3) then
|
||||
if((ndecodes-n2).eq.0) cycle
|
||||
lsubtract=.false.
|
||||
endif
|
||||
|
||||
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)
|
||||
do icand=1,ncand
|
||||
sync=candidate(3,icand)
|
||||
f1=candidate(1,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 ###
|
||||
call timer('ft8b ',0)
|
||||
call ft8b(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
|
||||
lsubtract,nagain,iaptype,mygrid6,bcontest,sync,f1,xdt,apsym, &
|
||||
nharderrors,dmin,nbadcrc,iappass,iera,message,xsnr)
|
||||
lsubtract,nagain,iaptype,mygrid6,bcontest,sync,f1,xdt,xbase, &
|
||||
apsym,nharderrors,dmin,nbadcrc,iappass,iera,message,xsnr)
|
||||
nsnr=nint(xsnr)
|
||||
xdt=xdt-0.5
|
||||
hd=nharderrors+dmin
|
||||
call timer('ft8b ',1)
|
||||
if(nbadcrc.eq.0) then
|
||||
call jtmsg(message,iflag)
|
||||
! call jtmsg(message,iflag)
|
||||
if(bcontest) call fix_contest_msg(mygrid6,message)
|
||||
if(iand(iflag,16).ne.0) message(22:22)='?'
|
||||
if(iand(iflag,15).eq.0) then
|
||||
ldupe=.false.
|
||||
do id=1,ndecodes
|
||||
if(message.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true.
|
||||
enddo
|
||||
if(.not.ldupe) then
|
||||
ndecodes=ndecodes+1
|
||||
allmessages(ndecodes)=message
|
||||
allsnrs(ndecodes)=nsnr
|
||||
endif
|
||||
! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
|
||||
! iflag,nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
|
||||
! xdt,nint(f1),message
|
||||
! flush(81)
|
||||
if(.not.ldupe .and. associated(this%callback)) then
|
||||
qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0]
|
||||
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)
|
||||
! if(iand(iflag,31).ne.0) message(22:22)='?'
|
||||
ldupe=.false.
|
||||
do id=1,ndecodes
|
||||
if(message.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true.
|
||||
enddo
|
||||
if(.not.ldupe) then
|
||||
ndecodes=ndecodes+1
|
||||
allmessages(ndecodes)=message
|
||||
allsnrs(ndecodes)=nsnr
|
||||
endif
|
||||
! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
|
||||
! nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
|
||||
! xdt,nint(f1),message
|
||||
!1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a22)
|
||||
! flush(81)
|
||||
if(.not.ldupe .and. associated(this%callback)) then
|
||||
qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0]
|
||||
call this%callback(sync,nsnr,xdt,f1,message,iaptype,qual)
|
||||
endif
|
||||
endif
|
||||
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);
|
||||
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)
|
||||
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);
|
||||
if (qsos.size()>0)
|
||||
@ -120,7 +120,7 @@ bool ADIF::match(QString const& call, QString const& band, QString const& mode)
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QString> ADIF::getCallList()
|
||||
QList<QString> ADIF::getCallList() const
|
||||
{
|
||||
QList<QString> p;
|
||||
QMultiHash<QString,QSO>::const_iterator i = _data.constBegin();
|
||||
@ -132,7 +132,7 @@ QList<QString> ADIF::getCallList()
|
||||
return p;
|
||||
}
|
||||
|
||||
int ADIF::getCount()
|
||||
int ADIF::getCount() const
|
||||
{
|
||||
return _data.size();
|
||||
}
|
||||
|
@ -21,18 +21,18 @@ class QDateTime;
|
||||
class ADIF
|
||||
{
|
||||
public:
|
||||
void init(QString const& filename);
|
||||
void load();
|
||||
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);
|
||||
QList<QString> getCallList();
|
||||
int getCount();
|
||||
void init(QString const& filename);
|
||||
void load();
|
||||
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) const;
|
||||
QList<QString> getCallList() const;
|
||||
int getCount() const;
|
||||
|
||||
// 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,
|
||||
QString const& comments, QString const& name, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid, QString const& m_txPower);
|
||||
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);
|
||||
|
||||
static QString bandFromFrequency(double dialFreq);
|
||||
static QString bandFromFrequency(double dialFreq);
|
||||
|
||||
private:
|
||||
struct QSO
|
||||
@ -43,7 +43,7 @@ class ADIF
|
||||
QMultiHash<QString, QSO> _data;
|
||||
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);
|
||||
}
|
||||
|
||||
bool CountriesWorked::getHasWorked(const QString countryName)
|
||||
bool CountriesWorked::getHasWorked(const QString countryName) const
|
||||
{
|
||||
if (_data.contains(countryName))
|
||||
return _data.value(countryName);
|
||||
@ -21,7 +21,7 @@ bool CountriesWorked::getHasWorked(const QString countryName)
|
||||
return false;
|
||||
}
|
||||
|
||||
int CountriesWorked::getWorkedCount()
|
||||
int CountriesWorked::getWorkedCount() const
|
||||
{
|
||||
int count = 0;
|
||||
foreach (bool value,_data)
|
||||
@ -30,7 +30,7 @@ int CountriesWorked::getWorkedCount()
|
||||
return count;
|
||||
}
|
||||
|
||||
int CountriesWorked::getSize()
|
||||
int CountriesWorked::getSize() const
|
||||
{
|
||||
return _data.count();
|
||||
}
|
||||
|
@ -14,15 +14,15 @@
|
||||
|
||||
class CountriesWorked
|
||||
{
|
||||
public:
|
||||
void init(const QStringList countryNames);
|
||||
void setAsWorked(const QString countryName);
|
||||
bool getHasWorked(const QString countryName);
|
||||
int getWorkedCount();
|
||||
int getSize();
|
||||
public:
|
||||
void init(const QStringList countryNames);
|
||||
void setAsWorked(const QString countryName);
|
||||
bool getHasWorked(const QString countryName) const;
|
||||
int getWorkedCount() const;
|
||||
int getSize() const;
|
||||
|
||||
private:
|
||||
QHash<QString, bool> _data;
|
||||
private:
|
||||
QHash<QString, bool> _data;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -26,7 +26,7 @@ void CountryDat::init(const QString filename)
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
QString CountryDat::_extractName(const QString line)
|
||||
QString CountryDat::_extractName(const QString line) const
|
||||
{
|
||||
int s1 = line.indexOf(':');
|
||||
if (s1>=0)
|
||||
@ -37,7 +37,7 @@ QString CountryDat::_extractName(const QString line)
|
||||
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);
|
||||
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.replace("=","");
|
||||
@ -117,7 +117,7 @@ void CountryDat::load()
|
||||
}
|
||||
|
||||
// return country name else ""
|
||||
QString CountryDat::find(QString prefix)
|
||||
QString CountryDat::find(QString prefix) const
|
||||
{
|
||||
prefix = prefix.toUpper ();
|
||||
auto pf = prefix;
|
||||
@ -143,6 +143,3 @@ QString CountryDat::find(QString prefix)
|
||||
}
|
||||
return QString {};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -19,13 +19,13 @@ class CountryDat
|
||||
public:
|
||||
void init(const QString filename);
|
||||
void load();
|
||||
QString find(QString prefix); // return country name or ""
|
||||
QStringList getCountryNames() { return _countryNames; };
|
||||
QString find(QString prefix) const; // return country name or ""
|
||||
QStringList getCountryNames() const { return _countryNames; };
|
||||
|
||||
private:
|
||||
QString _extractName(const QString line);
|
||||
void _removeBrackets(QString &line, const QString a, const QString b);
|
||||
QStringList _extractPrefix(QString &line, bool &more);
|
||||
QString _extractName(const QString line) const;
|
||||
void _removeBrackets(QString &line, const QString a, const QString b) const;
|
||||
QStringList _extractPrefix(QString &line, bool &more) const;
|
||||
|
||||
QString _filename;
|
||||
QStringList _countryNames;
|
||||
|
@ -67,7 +67,7 @@ void LogBook::_setAlreadyWorkedFromLog()
|
||||
void LogBook::match(/*in*/const QString call,
|
||||
/*out*/ QString &countryName,
|
||||
bool &callWorkedBefore,
|
||||
bool &countryWorkedBefore)
|
||||
bool &countryWorkedBefore) const
|
||||
{
|
||||
if (call.length() > 0)
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
void match(/*in*/ const QString call,
|
||||
/*out*/ QString &countryName,
|
||||
bool &callWorkedBefore,
|
||||
bool &countryWorkedBefore);
|
||||
bool &countryWorkedBefore) const;
|
||||
void addAsWorked(const QString call, const QString band, const QString mode, const QString date);
|
||||
|
||||
private:
|
||||
|
159
mainwindow.cpp
159
mainwindow.cpp
@ -42,6 +42,7 @@
|
||||
#include "widegraph.h"
|
||||
#include "sleep.h"
|
||||
#include "logqso.h"
|
||||
#include "decodedtext.h"
|
||||
#include "Radio.hpp"
|
||||
#include "Bands.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,
|
||||
SLOT(setFreq4(int,int)));
|
||||
|
||||
m_QSOText.clear();
|
||||
decodeBusy(false);
|
||||
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",
|
||||
@ -856,6 +856,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
|
||||
m_bDoubleClicked=false;
|
||||
m_bCallingCQ=false;
|
||||
m_wait=0;
|
||||
m_CQtype="CQ";
|
||||
|
||||
if(m_mode.startsWith ("WSPR") and m_pctx>0) {
|
||||
QPalette palette {ui->sbTxPercent->palette ()};
|
||||
@ -1190,8 +1191,7 @@ void MainWindow::dataSink(qint64 frames)
|
||||
int ftol = ui->sbFtol->value ();
|
||||
freqcal_(&dec_data.d2[0],&k,&nkhz,&RxFreq,&ftol,&line[0],80);
|
||||
QString t=QString::fromLatin1(line);
|
||||
DecodedText decodedtext;
|
||||
decodedtext=t;
|
||||
DecodedText decodedtext {t};
|
||||
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.DXCC(),
|
||||
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
|
||||
m_config.color_NewCall());
|
||||
@ -1425,10 +1425,8 @@ void MainWindow::fastSink(qint64 frames)
|
||||
m_fastGraph->plotSpec(m_diskData,m_UTCdisk);
|
||||
|
||||
if(bmsk144 and (line[0]!=0)) {
|
||||
DecodedText decodedtext;
|
||||
QString message;
|
||||
message=QString::fromLatin1(line);
|
||||
decodedtext=message.replace(QChar::LineFeed,"");
|
||||
QString message {QString::fromLatin1 (line)};
|
||||
DecodedText decodedtext {message.replace (QChar::LineFeed, "")};
|
||||
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.DXCC(),
|
||||
m_logBook,m_config.color_CQ(),m_config.color_MyCall(),m_config.color_DXCC(),
|
||||
m_config.color_NewCall());
|
||||
@ -1438,7 +1436,7 @@ void MainWindow::fastSink(qint64 frames)
|
||||
writeAllTxt(message);
|
||||
bool stdMsg = decodedtext.report(m_baseCall,
|
||||
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);
|
||||
}
|
||||
|
||||
@ -2569,8 +2567,7 @@ void::MainWindow::fast_decode_done()
|
||||
if(narg[13]/8==narg[12]) message=message.trimmed().replace("<...>",m_calls);
|
||||
|
||||
//Left (Band activity) window
|
||||
DecodedText decodedtext;
|
||||
decodedtext=message.replace(QChar::LineFeed,"");
|
||||
DecodedText decodedtext {message.replace (QChar::LineFeed, "")};
|
||||
if(!m_bFastDone) {
|
||||
ui->decodedTextBrowser->displayDecodedText (decodedtext,m_baseCall,m_config.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") {
|
||||
// find and extract any report for myCall
|
||||
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,
|
||||
Radio::base_callsign(ui->dxCallEntry->text()), m_rptRcvd);
|
||||
Radio::base_callsign(ui->dxCallEntry->text()), m_rptRcvd);
|
||||
|
||||
// extract details and send to PSKreporter
|
||||
if (stdMsg) pskPost(decodedtext);
|
||||
if (stdMsg) pskPost (decodedtext);
|
||||
}
|
||||
}
|
||||
m_startAnother=m_loopall;
|
||||
@ -2706,21 +2703,20 @@ void MainWindow::readFromStdout() //readFromStdout
|
||||
.arg (f.fileName ()).arg (f.errorString ()));
|
||||
}
|
||||
|
||||
if (m_config.insert_blank () && m_blankLine)
|
||||
{
|
||||
QString band;
|
||||
if (QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged > 50)
|
||||
{
|
||||
band = ' ' + m_config.bands ()->find (m_freqNominal);
|
||||
}
|
||||
ui->decodedTextBrowser->insertLineSpacer (band.rightJustified (40, '-'));
|
||||
m_blankLine = false;
|
||||
}
|
||||
if (m_config.insert_blank () && m_blankLine)
|
||||
{
|
||||
QString band;
|
||||
if (QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged > 50)
|
||||
{
|
||||
band = ' ' + m_config.bands ()->find (m_freqNominal);
|
||||
}
|
||||
ui->decodedTextBrowser->insertLineSpacer (band.rightJustified (40, '-'));
|
||||
m_blankLine = false;
|
||||
}
|
||||
|
||||
DecodedText decodedtext;
|
||||
decodedtext = QString::fromUtf8 (t.constData ()).remove (QRegularExpression {"\r|\n"});
|
||||
DecodedText decodedtext {QString::fromUtf8 (t.constData ()).remove (QRegularExpression {"\r|\n"})};
|
||||
|
||||
//Left (Band activity) window
|
||||
//Left (Band activity) window
|
||||
if(!bAvgMsg) {
|
||||
ui->decodedTextBrowser->displayDecodedText(decodedtext,m_baseCall,m_config.DXCC(),
|
||||
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();
|
||||
}
|
||||
m_QSOText=decodedtext;
|
||||
m_QSOText = decodedtext.string ();
|
||||
}
|
||||
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;
|
||||
|
||||
@ -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
|
||||
int i1=t1.lastIndexOf(QChar::LineFeed) + 1; //points to first char of line
|
||||
DecodedText decodedtext;
|
||||
QString t2 = messages.mid(i1,position-i1); //selected line
|
||||
|
||||
// basic mode sanity checks
|
||||
@ -3686,15 +3681,8 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
||||
}
|
||||
}
|
||||
}
|
||||
decodedtext = t2a;
|
||||
|
||||
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
|
||||
}
|
||||
DecodedText decodedtext {t2a};
|
||||
decodedtext.removeAddedInfo ();
|
||||
|
||||
auto t3 = decodedtext.string ();
|
||||
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 hisgrid;
|
||||
decodedtext.deCallAndGrid(/*out*/hiscall,hisgrid);
|
||||
if (!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")
|
||||
&& !(m_QSOProgress >= ROGER_REPORT && message_is_73 (0, t4)))
|
||||
bool is_73 = t4.filter (QRegularExpression {"^(73|RR73)$"}).size ();
|
||||
auto acceptable_73 =
|
||||
m_QSOProgress >= ROGER_REPORT
|
||||
&& is_73
|
||||
&& ((decodedtext.isStandardMessage ()
|
||||
&& (t4.contains (m_baseCall)
|
||||
|| 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;
|
||||
return;
|
||||
@ -3795,8 +3794,8 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
||||
}
|
||||
m_QSOProgress = SIGNOFF;
|
||||
} else if((m_QSOProgress >= REPORT
|
||||
|| (m_QSOProgress >= REPLYING && "MSK144" == m_mode && m_config.contestMode ()))
|
||||
&& r.mid(0,1)=="R") {
|
||||
|| (m_QSOProgress >= REPLYING && (m_mode=="MSK144" or m_mode=="FT8")
|
||||
&& m_config.contestMode ())) && r.mid(0,1)=="R") {
|
||||
m_ntx=4;
|
||||
m_QSOProgress = ROGERS;
|
||||
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)) {
|
||||
if ((t4.size () >= 9 && t4.at (5).contains (m_baseCall) && t4.at (8) == "OOO")
|
||||
|| (m_mode=="MSK144" && m_config.contestMode())) {
|
||||
// EME short code report or MSK144 contest mode reply, send back Tx3
|
||||
|| ((m_mode=="MSK144" or m_mode=="FT8") && m_config.contestMode())) {
|
||||
// EME short code report or MSK144/FT8 contest mode reply, send back Tx3
|
||||
m_ntx = 3;
|
||||
m_QSOProgress = ROGER_REPORT;
|
||||
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) {
|
||||
gen_msg = 5;
|
||||
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 (m_bAutoReply) m_bCallingCQ = CALLING == m_QSOProgress;
|
||||
QString s1=m_QSOText.string().trimmed();
|
||||
QString s1 = m_QSOText.trimmed ();
|
||||
QString s2=t2.trimmed();
|
||||
if (s1!=s2 and !decodedtext.isTX()) {
|
||||
decodedtext=t2;
|
||||
decodedtext = DecodedText {t2};
|
||||
ui->decodedTextBrowser2->displayDecodedText(decodedtext, m_baseCall,
|
||||
false, m_logBook,m_config.color_CQ(), m_config.color_MyCall(),
|
||||
m_config.color_DXCC(),m_config.color_NewCall());
|
||||
m_QSOText=decodedtext;
|
||||
m_QSOText = decodedtext.string ();
|
||||
}
|
||||
|
||||
if (hiscall != "73"
|
||||
@ -4000,34 +3999,27 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
|
||||
|
||||
void MainWindow::genCQMsg ()
|
||||
{
|
||||
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 ();
|
||||
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'})
|
||||
.arg (m_config.my_callsign())
|
||||
.arg (grid.left (4)),
|
||||
ui->tx6);
|
||||
}
|
||||
else
|
||||
{
|
||||
msgtype (QString {"CQ %1 %2"}.arg (m_config.my_callsign ()).arg (grid.left (4)), ui->tx6);
|
||||
}
|
||||
if ((m_mode=="JT4" or m_mode=="QRA64") and ui->cbShMsgs->isChecked()) {
|
||||
if (ui->cbTx6->isChecked ()) {
|
||||
msgtype ("@1250 (SEND MSGS)", ui->tx6);
|
||||
}
|
||||
else {
|
||||
msgtype ("@1000 (TUNE)", ui->tx6);
|
||||
}
|
||||
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 ();
|
||||
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'})
|
||||
.arg (m_config.my_callsign())
|
||||
.arg (grid.left (4)),
|
||||
ui->tx6);
|
||||
} else {
|
||||
msgtype (QString {"%1 %2 %3"}.arg(m_CQtype).arg(m_config.my_callsign()).arg(grid.left(4)),ui->tx6);
|
||||
}
|
||||
if ((m_mode=="JT4" or m_mode=="QRA64") and ui->cbShMsgs->isChecked()) {
|
||||
if (ui->cbTx6->isChecked ()) {
|
||||
msgtype ("@1250 (SEND MSGS)", ui->tx6);
|
||||
} else {
|
||||
msgtype ("@1000 (TUNE)", ui->tx6);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->tx6->clear ();
|
||||
}
|
||||
} else {
|
||||
ui->tx6->clear ();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::genStdMsgs(QString rpt, bool unconditional)
|
||||
@ -4189,6 +4181,10 @@ void MainWindow::TxAgain()
|
||||
|
||||
void MainWindow::clearDX ()
|
||||
{
|
||||
if (m_QSOProgress != CALLING)
|
||||
{
|
||||
auto_tx_mode (false);
|
||||
}
|
||||
ui->dxCallEntry->clear ();
|
||||
ui->dxGridEntry->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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@
|
||||
#include "DisplayManual.hpp"
|
||||
#include "psk_reporter.h"
|
||||
#include "logbook/logbook.h"
|
||||
#include "decodedtext.h"
|
||||
#include "commons.h"
|
||||
#include "astro.h"
|
||||
#include "MessageBox.hpp"
|
||||
@ -82,6 +81,7 @@ class Detector;
|
||||
class SampleDownloader;
|
||||
class MultiSettings;
|
||||
class EqualizationToolsDialog;
|
||||
class DecodedText;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
@ -532,6 +532,7 @@ private:
|
||||
QString m_msgSent0;
|
||||
QString m_fileToSave;
|
||||
QString m_calls;
|
||||
QString m_CQtype;
|
||||
|
||||
QSet<QString> m_pfx;
|
||||
QSet<QString> m_sfx;
|
||||
@ -540,7 +541,7 @@ private:
|
||||
|
||||
QSharedMemory *mem_jt9;
|
||||
LogBook m_logBook;
|
||||
DecodedText m_QSOText;
|
||||
QString m_QSOText;
|
||||
unsigned m_msAudioOutputBuffered;
|
||||
unsigned m_framesAudioInputBuffered;
|
||||
unsigned m_downSampleFactor;
|
||||
@ -587,7 +588,7 @@ private:
|
||||
void transmit (double snr = 99.);
|
||||
void rigFailure (QString const& reason);
|
||||
void pskSetLocal ();
|
||||
void pskPost(DecodedText decodedtext);
|
||||
void pskPost(DecodedText const& decodedtext);
|
||||
void displayDialFrequency ();
|
||||
void transmitDisplay (bool);
|
||||
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/>
|
||||
decoded signal's frequency; generate standard messages.<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/>
|
||||
Hold down Alt to only move the Rx frequency when<br/>
|
||||
double-clicking to reply to a CQ or QRZ caller.
|
||||
<b>Alt-Double-click</b> to move only Rx frequency when<br/>
|
||||
replying to a CQ or QRZ caller.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
Loading…
x
Reference in New Issue
Block a user