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/azdist.f90
lib/badmsg.f90
lib/fsk4hf/baseline.f90
lib/bpdecode40.f90
lib/bpdecode144.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>
</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>

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);
}
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,19 +92,13 @@ 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
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 ()
@ -84,7 +109,7 @@ bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /
QString tt="";
if(w.size() > 2) tt=w[2];
bool ok;
i1=tt.toInt(&ok);
auto i1=tt.toInt(&ok);
if (ok and i1>=-50 and i1<50)
{
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
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)

View File

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

View File

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

View File

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

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

View File

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

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

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

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

View File

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

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

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'
! 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)

View File

@ -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,40 +68,45 @@ 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
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.
syncmin=1.5
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
! 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.
@ -111,20 +117,14 @@ contains
allsnrs(ndecodes)=nsnr
endif
! 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
!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
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
enddo
! 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);
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();
}

View File

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

View File

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

View File

@ -17,9 +17,9 @@ class CountriesWorked
public:
void init(const QStringList countryNames);
void setAsWorked(const QString countryName);
bool getHasWorked(const QString countryName);
int getWorkedCount();
int getSize();
bool getHasWorked(const QString countryName) const;
int getWorkedCount() const;
int getSize() const;
private:
QHash<QString, bool> _data;

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
// extract details and send to PSKreporter
if (stdMsg) pskPost(decodedtext);
if (stdMsg) pskPost (decodedtext);
}
}
m_startAnother=m_loopall;
@ -2717,8 +2714,7 @@ void MainWindow::readFromStdout() //readFromStdout
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
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();
}
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
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")
&& !(m_QSOProgress >= ROGER_REPORT && message_is_73 (0, t4)))
&& 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,32 +3999,25 @@ void MainWindow::processMessage(QString const& messages, int position, bool ctrl
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 ();
if (ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked ())
{
if (ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked ()) {
msgtype (QString {"CQ %1 %2 %3"}
.arg (m_freqNominal / 1000 - m_freqNominal / 1000000 * 1000, 3, 10, QChar {'0'})
.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);
} 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 {
} else {
msgtype ("@1000 (TUNE)", ui->tx6);
}
}
}
else
{
} else {
ui->tx6->clear ();
}
}
@ -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);
}

View File

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

View File

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