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:
Bill Somerville 2017-08-31 00:41:52 +00:00
parent 3c996b01dc
commit f72a40d5bc
31 changed files with 3224 additions and 1244 deletions

View File

@ -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

View File

@ -2342,7 +2342,7 @@ Right click for insert and delete options.</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Exchange 4-character grid locators instead of reports. See User Guide for details.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Exchange 4-character grid locators instead of reports. See User Guide for details.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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>

3281
cty.dat

File diff suppressed because it is too large Load Diff

View File

@ -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,19 +92,13 @@ 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 ()
@ -84,7 +109,7 @@ bool DecodedText::report(QString const& myBaseCall, QString const& 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;
@ -101,22 +126,22 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /
} }
} }
} }
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)

View File

@ -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

View File

@ -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)
{ {

View File

@ -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_;

View File

@ -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,

View File

@ -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"]

View File

@ -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

View File

@ -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

View File

@ -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
View 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

View File

@ -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
View 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

View File

@ -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
@ -154,31 +154,30 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
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

View File

@ -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

View File

@ -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,28 +92,149 @@ 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
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
iend=1
endif
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
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
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) me=ieor(m0,mi)
call mrbencode(me,ce,g2,N,K) call mrbencode(me,ce,g2,N,K)
nxor=ieor(ce,hdec) nxor=ieor(ce,hdec)
@ -126,25 +243,19 @@ do iorder=1,norder
dmin=dd dmin=dd
cw=ce cw=ce
nhardmin=sum(nxor) nhardmin=sum(nxor)
thresh=rho*dmin
endif endif
else goto 778
nrejected=nrejected+1
endif 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 enddo
enddo call nextpat(misub,K,nord,iflag)
enddo
endif
!write(*,*) 'nhardmin ',nhardmin 998 continue
!write(*,*) 'total patterns ',nt,' number rejected ',nrejected ! Re-order the codeword to place message bits at the end.
! 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

View File

@ -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)

View File

@ -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,40 +68,45 @@ 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.
@ -111,20 +117,14 @@ contains
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, &
! iflag,nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), & ! 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 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
enddo enddo
! h=default_header(12000,NMAX) ! h=default_header(12000,NMAX)

View File

@ -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();
} }

View File

@ -24,9 +24,9 @@ class ADIF
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,
@ -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;
}; };

View File

@ -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();
} }

View File

@ -17,9 +17,9 @@ 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;

View File

@ -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 {};
} }

View File

@ -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;

View File

@ -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)
{ {

View File

@ -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:

View File

@ -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;
@ -2717,8 +2714,7 @@ void MainWindow::readFromStdout() //readFromStdout
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) {
@ -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 ();
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.size () == 7 // unless it is of the form
&& (t4.at (5) == m_baseCall // "<our-call> 73" && (t4.at (5) == m_baseCall // "<our-call> 73"
|| t4.at (5).startsWith (m_baseCall + '/') || t4.at (5).startsWith (m_baseCall + '/')
|| t4.at (5).endsWith ('/' + m_baseCall)) || t4.at (5).endsWith ('/' + m_baseCall))
&& t4.at (6) == "73") && t4.at (6) == "73")))
&& !(m_QSOProgress >= ROGER_REPORT && message_is_73 (0, t4)))
{ {
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,32 +3999,25 @@ 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"} msgtype (QString {"CQ %1 %2 %3"}
.arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'}) .arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'})
.arg (m_config.my_callsign()) .arg (m_config.my_callsign())
.arg (grid.left (4)), .arg (grid.left (4)),
ui->tx6); ui->tx6);
} } else {
else msgtype (QString {"%1 %2 %3"}.arg(m_CQtype).arg(m_config.my_callsign()).arg(grid.left(4)),ui->tx6);
{
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 ((m_mode=="JT4" or m_mode=="QRA64") and ui->cbShMsgs->isChecked()) {
if (ui->cbTx6->isChecked ()) { if (ui->cbTx6->isChecked ()) {
msgtype ("@1250 (SEND MSGS)", ui->tx6); msgtype ("@1250 (SEND MSGS)", ui->tx6);
} } else {
else {
msgtype ("@1000 (TUNE)", ui->tx6); msgtype ("@1000 (TUNE)", ui->tx6);
} }
} }
} } else {
else
{
ui->tx6->clear (); ui->tx6->clear ();
} }
} }
@ -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);
} }

View File

@ -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);

View File

@ -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>