Compare commits

..

17 Commits

Author SHA1 Message Date
Joe Taylor
2b9d65408d Bug fix: correct the misuse of variable 'ncand' in both q65 module and a common block. 2024-03-12 08:47:23 -04:00
Uwe Risse
c5a266b5e0 Update Catalan translation of the UI. Thanks to Xavi, EA3W. 2024-03-07 18:15:02 +01:00
Uwe Risse
de9dc8e3fb Minor changes to the Release Notes. 2024-03-07 17:22:40 +01:00
Uwe Risse
5e410a982b Further updates to the Spanish translation of the UI. Thanks to Cedrik, EA4AC. 2024-03-07 16:42:05 +01:00
Uwe Risse
2a9d0b6998 Update Spanish translation of the UI. 2024-03-07 11:17:16 +01:00
Uwe Risse
75f6b9b423 Fix a compilation error. 2024-03-07 01:14:11 +01:00
Uwe Risse
c7a93fca4a Code cleanup. 2024-03-04 10:50:17 +01:00
Uwe Risse
08785eff56 Update NEWS and Release Note for RC4. 2024-03-04 10:28:03 +01:00
Uwe Risse
40fbc208fd Code cleanup. 2024-03-04 10:27:14 +01:00
Uwe Risse
1ac2fc23c3 Remove unused code. 2024-03-04 10:14:54 +01:00
Uwe Risse
d4a5ea60e6 Preparations for RC4. 2024-03-04 10:00:03 +01:00
Uwe Risse
86fd50304f Remove unused code. 2024-03-04 09:58:32 +01:00
Uwe Risse
75b4e0e798 Remove unused code. 2024-03-04 09:45:59 +01:00
Joe Taylor
ee68285583 Revert "Bare-bones foxgen2 is now functional and parsing normal Fox messages."
This reverts commit b83c41c8deec1b09d56f504c0fd09e9b693d8184.
2024-03-01 16:40:16 -05:00
Joe Taylor
ae50058498 Revert "Fix two typos."
This reverts commit 72651037bdec5410272654699bbbf90edbc89f17.
2024-03-01 16:40:14 -05:00
Joe Taylor
587a16cd21 Revert "WIP on assembling SuperFox messages."
This reverts commit 4c0d34477d137ef57fa03def5cd5e1997717952e.
2024-03-01 16:40:12 -05:00
Joe Taylor
45151bda3b Revert "SuperFox messages are now properly assembled at uset level. Next, need to encode."
This reverts commit 34b97b53f82bd75a87fa1b302a325d3e71d494af.
2024-03-01 16:40:01 -05:00
108 changed files with 12160 additions and 16838 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ GTAGS
*~
junk*
jnq*
*.exe
*.o
*.mod
*.pro.user

View File

@ -148,6 +148,7 @@ void SoundOutput::stop ()
m_stream->reset ();
m_stream->stop ();
}
m_stream.reset ();
}
qreal SoundOutput::attenuation () const

View File

@ -50,7 +50,6 @@ project (wsjtx
)
set (PROJECT_DESCRIPTION "WSJT-X: Digital Modes for Weak Signal Communications in Amateur Radio")
set (CMAKE_PROJECT_DESCRIPTION ${PROJECT_DESCRIPTION})
set (CMAKE_AUTOUIC ON)
#
# Local CMake modules and support files
@ -72,7 +71,7 @@ message (STATUS "******************************************************")
include (set_build_type)
# RC 0 or omitted is a development build, GA is a General Availability release build
set_build_type (RC 7)
set_build_type (RC 4)
set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}")
#
@ -81,7 +80,7 @@ set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_
set (PROJECT_BUNDLE_NAME "WSJT-X")
set (PROJECT_VENDOR "Joe Taylor, K1JT")
set (PROJECT_CONTACT "Joe Taylor <k1jt@arrl.net>")
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2024 by Joe Taylor, K1JT")
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2023 by Joe Taylor, K1JT")
set (PROJECT_HOMEPAGE https://wsjt.sourceforge.io/wsjtx.html)
set (PROJECT_MANUAL wsjtx-main)
set (PROJECT_MANUAL_DIRECTORY_URL https://wsjt.sourceforge.io/wsjtx-doc/)
@ -127,7 +126,6 @@ option (WSJT_GENERATE_DOCS "Generate documentation files." ON)
option (WSJT_RIG_NONE_CAN_SPLIT "Allow split operation with \"None\" as rig.")
option (WSJT_TRACE_UDP "Debugging option that turns on UDP message protocol diagnostics.")
option (WSJT_BUILD_UTILS "Build simulators and code demonstrators." ON)
option (WSJT_FOX_OTP "Enable Fox OTP Verification Messages." ON)
CMAKE_DEPENDENT_OPTION (WSJT_QDEBUG_IN_RELEASE "Leave Qt debugging statements in Release configuration." OFF
"NOT is_debug_build" OFF)
CMAKE_DEPENDENT_OPTION (WSJT_ENABLE_EXPERIMENTAL_FEATURES "Enable features not fully ready for public releases." ON
@ -163,13 +161,6 @@ endif ()
set (WSJT_PLUGIN_DESTINATION ${PLUGIN_DESTINATION} CACHE PATH "Path for plugins")
set (WSJT_QT_CONF_DESTINATION ${QT_CONF_DESTINATION} CACHE PATH "Path for the qt.conf file")
if (WSJT_FOX_OTP)
set (wsjt_fox_CXXSRCS
)
message (STATUS "Including Fox verification code feature")
endif ()
#
# Project sources
#
@ -231,7 +222,6 @@ set (wsjt_qt_CXXSRCS
widgets/DoubleClickableRadioButton.cpp
Network/LotWUsers.cpp
Network/FileDownload.cpp
Network/FoxVerifier.cpp
models/DecodeHighlightingModel.cpp
widgets/DecodeHighlightingListView.cpp
models/FoxLog.cpp
@ -251,7 +241,6 @@ set (wsjt_qt_CXXSRCS
widgets/LazyFillComboBox.cpp
widgets/CheckableItemComboBox.cpp
widgets/BandComboBox.cpp
otpgenerator.cpp
)
set (wsjt_qtmm_CXXSRCS
@ -302,7 +291,6 @@ set (wsjt_CXXSRCS
lib/crc10.cpp
lib/crc13.cpp
lib/crc14.cpp
${wsjt_fox_CXXSRCS}
)
# deal with a GCC v6 UB error message
set_source_files_properties (
@ -353,10 +341,6 @@ set (wsjt_FSRCS
lib/wavhdr.f90
lib/qra/q65/q65_encoding_modules.f90
lib/ft8/ft8_a7.f90
lib/superfox/sfox_mod.f90
lib/superfox/julian.f90
lib/superfox/popen_module.f90
lib/superfox/qpc/qpc_mod.f90
# remaining non-module sources
lib/addit.f90
@ -442,7 +426,7 @@ set (wsjt_FSRCS
lib/fspread_lorentz.f90
lib/ft8/foxfilt.f90
lib/ft8/foxgen.f90
# lib/ft8/foxgen_wrap.f90
lib/ft8/foxgen_wrap.f90
lib/freqcal.f90
lib/ft8/ft8apset.f90
lib/ft8/ft8b.f90
@ -601,27 +585,6 @@ set (wsjt_FSRCS
lib/fst4/get_crc24.f90
lib/fst4/fst4_baseline.f90
lib/77bit/hash22calc.f90
lib/superfox/foxgen2.f90
lib/superfox/qpc_decode2.f90
lib/superfox/qpc_likelihoods2.f90
lib/superfox/qpc_snr.f90
lib/superfox/qpc_sync.f90
lib/superfox/sfox_ana.f90
lib/superfox/sfox_assemble.f90
lib/superfox/sfox_demod.f90
lib/superfox/sfox_pack.f90
lib/superfox/sfox_remove_ft8.f90
lib/superfox/sfox_remove_tone.f90
lib/superfox/sfox_unpack.f90
lib/superfox/sfox_wave.f90
lib/superfox/sfox_wave_gfsk.f90
lib/superfox/sfrx_sub.f90
lib/superfox/sftx_sub.f90
lib/superfox/twkfreq2.f90
lib/superfox/sfox_gen_gfsk.f90
lib/superfox/ran1.f90
lib/superfox/sfoxsim.f90
)
# temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit
@ -664,15 +627,6 @@ set (wsjt_CSRCS
lib/wrapkarn.c
${ldpc_CSRCS}
${qra_CSRCS}
lib/superfox/qpc/dbgprintf.c
lib/superfox/qpc/nhash2.c
lib/superfox/qpc/np_qpc.c
lib/superfox/qpc/np_rnd.c
lib/superfox/qpc/qpc_fwht.c
lib/superfox/qpc/qpc_n127k50q128.c
lib/superfox/qpc/qpc_subs.c
)
set (wsjt_qt_UISRCS
@ -946,9 +900,7 @@ check_type_size (CACHE_ALL HAMLIB_OLD_CACHING)
check_symbol_exists (rig_set_cache_timeout_ms "hamlib/rig.h" HAVE_HAMLIB_CACHING)
find_package (Usb REQUIRED)
if (WSJT_FOX_OTP)
add_definitions (-DFOX_OTP)
endif ()
#
# Qt5 setup
#
@ -1201,9 +1153,6 @@ target_link_libraries (test_snr wsjt_fort)
add_executable (q65sim lib/qra/q65/q65sim.f90)
target_link_libraries (q65sim wsjt_fort wsjt_cxx)
add_executable (cwsim lib/cwsim.f90)
target_link_libraries (cwsim wsjt_fort wsjt_cxx)
add_executable (q65code lib/qra/q65/q65code.f90)
target_link_libraries (q65code wsjt_fort wsjt_cxx)
@ -1258,15 +1207,6 @@ target_link_libraries (echosim wsjt_fort wsjt_cxx)
add_executable (ft8sim lib/ft8/ft8sim.f90)
target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
add_executable (sfoxsim lib/superfox/sfoxsim.f90)
target_link_libraries (sfoxsim wsjt_fort wsjt_cxx)
add_executable (sfrx lib/superfox/sfrx.f90)
target_link_libraries (sfrx wsjt_fort wsjt_cxx)
#add_executable (sftx lib/superfox/sftx.f90)
#target_link_libraries (sftx wsjt_fort wsjt_cxx)
add_executable (msk144sim lib/msk144sim.f90)
target_link_libraries (msk144sim wsjt_fort wsjt_cxx)
@ -1351,7 +1291,9 @@ set (LANGUAGES
ru # Russian
#sv # Swedish
zh # Chinese
zh_HK # Chinese per Hong Kong
zh_TW # Chinese traditional
it # Italian
)
foreach (lang_ ${LANGUAGES})
file (TO_NATIVE_PATH ${CMAKE_SOURCE_DIR}/translations/wsjtx_${lang_}.ts ts_)

View File

@ -193,7 +193,6 @@
#include "models/FrequencyList.hpp"
#include "models/StationList.hpp"
#include "Network/NetworkServerLookup.hpp"
#include "Network/FoxVerifier.hpp"
#include "widgets/MessageBox.hpp"
#include "validators/MaidenheadLocatorValidator.hpp"
#include "validators/CallsignValidator.hpp"
@ -280,7 +279,6 @@ namespace
constexpr quint32 qrg_version_100 {100};
}
//
// Dialog to get a new Frequency item
//
@ -388,7 +386,6 @@ private:
QDateTimeEdit *start_date_time_edit_;
};
//
// Dialog to get a new Station item
//
@ -461,9 +458,6 @@ public:
}
};
// Internal implementation of the Configuration class.
class Configuration::impl final
: public QDialog
@ -585,25 +579,9 @@ private:
Q_SLOT void on_LotW_CSV_fetch_push_button_clicked (bool);
Q_SLOT void on_hamlib_download_button_clicked (bool);
Q_SLOT void on_revert_update_button_clicked (bool);
Q_SLOT void on_gbSpecialOpActivity_clicked (bool);
Q_SLOT void on_rbFox_clicked (bool);
Q_SLOT void on_rbHound_clicked (bool);
Q_SLOT void on_rbNA_VHF_Contest_clicked (bool);
Q_SLOT void on_rbEU_VHF_Contest_clicked (bool);
Q_SLOT void on_rbWW_DIGI_clicked (bool);
Q_SLOT void on_rbQ65pileup_clicked (bool);
Q_SLOT void on_rbField_Day_clicked (bool);
Q_SLOT void on_rbRTTY_Roundup_clicked (bool);
Q_SLOT void on_rbARRL_Digi_clicked (bool);
Q_SLOT void on_cbSuperFox_clicked (bool);
Q_SLOT void on_cbContestName_clicked (bool);
Q_SLOT void on_cbOTP_clicked (bool);
Q_SLOT void on_cbShowOTP_clicked (bool);
void error_during_hamlib_download (QString const& reason);
void after_hamlib_downloaded();
void display_file_information();
void check_visibility();
Q_SLOT void on_cbx2ToneSpacing_clicked(bool);
Q_SLOT void on_cbx4ToneSpacing_clicked(bool);
@ -611,8 +589,6 @@ private:
Q_SLOT void on_cbAutoLog_clicked(bool);
Q_SLOT void on_Field_Day_Exchange_textEdited (QString const&);
Q_SLOT void on_RTTY_Exchange_textEdited (QString const&);
Q_SLOT void on_OTPUrl_textEdited (QString const&);
Q_SLOT void on_OTPSeed_textEdited (QString const&);
Q_SLOT void on_Contest_Name_textEdited (QString const&);
// typenames used as arguments must match registered type names :(
@ -712,12 +688,6 @@ private:
QString Contest_Name_;
QString hamlib_backed_up_;
QString OTPUrl_;
QString OTPSeed_;
bool OTPEnabled_;
bool ShowOTP_;
qint32 OTPinterval_;
qint32 id_interval_;
qint32 ntrials_;
qint32 aggressive_;
@ -750,7 +720,6 @@ private:
bool decode_at_52s_;
bool single_decode_;
bool twoPass_;
bool bSuperFox_;
bool Individual_Contest_Name_;
bool bSpecialOp_;
int SelectedActivity_;
@ -792,7 +761,6 @@ private:
#include "Configuration.moc"
// delegate to implementation class
Configuration::Configuration (QNetworkAccessManager * network_manager, QDir const& temp_directory,
QSettings * settings, LogBook * logbook, QWidget * parent)
@ -859,7 +827,6 @@ bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features
bool Configuration::decode_at_52s () const {return m_->decode_at_52s_;}
bool Configuration::single_decode () const {return m_->single_decode_;}
bool Configuration::twoPass() const {return m_->twoPass_;}
bool Configuration::superFox() const {return m_->bSuperFox_;}
bool Configuration::Individual_Contest_Name() const {return m_->Individual_Contest_Name_;}
bool Configuration::x2ToneSpacing() const {return m_->x2ToneSpacing_;}
bool Configuration::x4ToneSpacing() const {return m_->x4ToneSpacing_;}
@ -988,26 +955,6 @@ void Configuration::invalidate_audio_output_device (QString /* error */)
m_->audio_output_device_ = QAudioDeviceInfo {};
}
// OTP seed can be empty, in which case it is not used, or a valid 16 character base32 string.
bool Configuration::validate_otp_seed(QString seed)
{
if (seed.isEmpty())
{
return true;
}
if (seed.size() != 16)
{
return false;
}
for (QChar c: seed)
{
if (!QString(BASE32_CHARSET).contains(c))
{
return false;
}
}
return true;
}
bool Configuration::valid_n1mm_info () const
{
// do very rudimentary checking on the n1mm server name and port number.
@ -1097,43 +1044,6 @@ void Configuration::setSpecial_None()
m_->SelectedActivity_ = static_cast<int> (SpecialOperatingActivity::HOUND); // brings backward compatibility to versions without Q65_PILEUP
m_->write_settings();
}
void Configuration::toggle_SF()
{
if (m_->bSuperFox_) {
m_->ui_->cbSuperFox->setChecked(false);
} else {
m_->ui_->cbSuperFox->setChecked(true);
}
m_->bSuperFox_ = m_->ui_->cbSuperFox->isChecked ();
m_->write_settings();
}
QString Configuration::OTPSeed() const
{
return m_->OTPSeed_;
}
QString Configuration::OTPUrl() const
{
return m_->OTPUrl_;
}
unsigned int Configuration::OTPinterval() const
{
return m_->OTPinterval_;
}
bool Configuration::OTPEnabled() const
{
return m_->OTPSeed_.size() == 16 && m_->OTPEnabled_;
}
bool Configuration::ShowOTP () const
{
return m_->ShowOTP_;
}
namespace
{
#if defined (Q_OS_MAC)
@ -1304,8 +1214,6 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
ui_->add_macro_line_edit->setValidator (new QRegularExpressionValidator {message_alphabet, this});
ui_->Field_Day_Exchange->setValidator (new QRegularExpressionValidator {field_day_exchange_re, this});
ui_->RTTY_Exchange->setValidator (new QRegularExpressionValidator {RTTY_roundup_exchange_re, this});
QRegularExpression b32(QString("(^[") + QString(BASE32_CHARSET)+QString(BASE32_CHARSET).toLower() + QString("]{16}$)|(^$)"));
ui_->OTPSeed->setValidator(new QRegularExpressionValidator(b32, this));
//
// assign ids to radio buttons
@ -1549,7 +1457,6 @@ void Configuration::impl::initialize_models ()
ui_->decode_at_52s_check_box->setChecked(decode_at_52s_);
ui_->single_decode_check_box->setChecked(single_decode_);
ui_->cbTwoPass->setChecked(twoPass_);
ui_->cbSuperFox->setChecked(bSuperFox_);
ui_->cbContestName->setChecked(Individual_Contest_Name_);
ui_->gbSpecialOpActivity->setChecked(bSpecialOp_);
ui_->special_op_activity_button_group->button (SelectedActivity_)->setChecked (true);
@ -1633,8 +1540,6 @@ void Configuration::impl::initialize_models ()
ui_->cbHighlightDXcall->setChecked(highlight_DXcall_);
ui_->cbHighlightDXgrid->setChecked(highlight_DXgrid_);
check_visibility ();
set_rig_invariants ();
}
@ -1669,19 +1574,6 @@ void Configuration::impl::read_settings ()
ui_->Contest_Name->setText(Contest_Name_);
hamlib_backed_up_ = settings_->value ("HamlibBackedUp",QString {}).toString ();
OTPinterval_ = settings_->value ("OTPinterval", 1).toUInt ();
OTPUrl_ = settings_->value ("OTPUrl", FoxVerifier::default_url()).toString ();
OTPSeed_ = settings_->value ("OTPSeed", QString {}).toString ();
OTPEnabled_ = settings_->value ("OTPEnabled", false).toBool ();
ShowOTP_ = settings_->value ("ShowOTP", false).toBool ();
ui_->sbOTPinterval->setValue(OTPinterval_);
ui_->OTPUrl->setText(OTPUrl_);
ui_->OTPSeed->setText(OTPSeed_);
ui_->cbOTP->setChecked(OTPEnabled_);
ui_->cbShowOTP->setChecked(ShowOTP_);
if (next_font_.fromString (settings_->value ("Font", QGuiApplication::font ().toString ()).toString ())
&& next_font_ != font_)
{
@ -1833,7 +1725,6 @@ void Configuration::impl::read_settings ()
decode_at_52s_ = settings_->value("Decode52",false).toBool ();
single_decode_ = settings_->value("SingleDecode",false).toBool ();
twoPass_ = settings_->value("TwoPass",true).toBool ();
bSuperFox_ = settings_->value("SuperFox",true).toBool ();
Individual_Contest_Name_ = settings_->value("Individual_Contest_Name",true).toBool ();
bSpecialOp_ = settings_->value("SpecialOpActivity",false).toBool ();
SelectedActivity_ = settings_->value("SelectedActivity",1).toInt ();
@ -1982,7 +1873,6 @@ void Configuration::impl::write_settings ()
settings_->setValue ("Decode52", decode_at_52s_);
settings_->setValue ("SingleDecode", single_decode_);
settings_->setValue ("TwoPass", twoPass_);
settings_->setValue ("SuperFox", bSuperFox_);
settings_->setValue ("Individual_Contest_Name", Individual_Contest_Name_);
settings_->setValue ("SelectedActivity", SelectedActivity_);
settings_->setValue ("SpecialOpActivity", bSpecialOp_);
@ -2007,11 +1897,6 @@ void Configuration::impl::write_settings ()
settings_->setValue ("AutoGrid", use_dynamic_grid_);
settings_->setValue ("highlight_DXcall", highlight_DXcall_);
settings_->setValue ("highlight_DXgrid", highlight_DXgrid_);
settings_->setValue ("OTPinterval", OTPinterval_);
settings_->setValue ("OTPUrl", OTPUrl_);
settings_->setValue ("OTPSeed", OTPSeed_);
settings_->setValue ("OTPEnabled", OTPEnabled_);
settings_->setValue ("ShowOTP", ShowOTP_);
settings_->sync ();
}
@ -2417,7 +2302,6 @@ void Configuration::impl::accept ()
decode_at_52s_ = ui_->decode_at_52s_check_box->isChecked ();
single_decode_ = ui_->single_decode_check_box->isChecked ();
twoPass_ = ui_->cbTwoPass->isChecked ();
bSuperFox_ = ui_->cbSuperFox->isChecked ();
Individual_Contest_Name_ = ui_->cbContestName->isChecked ();
bSpecialOp_ = ui_->gbSpecialOpActivity->isChecked ();
SelectedActivity_ = ui_->special_op_activity_button_group->checkedId();
@ -2428,11 +2312,6 @@ void Configuration::impl::accept ()
pwrBandTxMemory_ = ui_->checkBoxPwrBandTxMemory->isChecked ();
pwrBandTuneMemory_ = ui_->checkBoxPwrBandTuneMemory->isChecked ();
opCall_=ui_->opCallEntry->text();
OTPinterval_=ui_->sbOTPinterval->value();
OTPSeed_=ui_->OTPSeed->text();
OTPUrl_=ui_->OTPUrl->text();
OTPEnabled_=ui_->cbOTP->isChecked();
ShowOTP_=ui_->cbShowOTP->isChecked();
auto new_server = ui_->udp_server_line_edit->text ().trimmed ();
auto new_interfaces = get_selected_network_interfaces (ui_->udp_interfaces_combo_box);
@ -3222,160 +3101,6 @@ void Configuration::impl::on_cbx4ToneSpacing_clicked(bool b)
if(b) ui_->cbx2ToneSpacing->setChecked(false);
}
void Configuration::impl::on_gbSpecialOpActivity_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbFox_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbHound_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbNA_VHF_Contest_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbEU_VHF_Contest_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbWW_DIGI_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbQ65pileup_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbField_Day_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbRTTY_Roundup_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_rbARRL_Digi_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_cbSuperFox_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_cbContestName_clicked (bool)
{
check_visibility ();
}
void Configuration::impl::on_cbOTP_clicked(bool)
{
check_visibility();
}
void Configuration::impl::on_cbShowOTP_clicked(bool)
{
check_visibility();
}
void Configuration::impl::check_visibility ()
{
if (ui_->rbField_Day->isChecked() and ui_->gbSpecialOpActivity->isChecked()) {
ui_->labFD->setEnabled (true);
ui_->Field_Day_Exchange->setEnabled (true);
} else {
ui_->labFD->setEnabled (false);
ui_->Field_Day_Exchange->setEnabled (false);
}
if (ui_->rbRTTY_Roundup->isChecked() and ui_->gbSpecialOpActivity->isChecked()) {
ui_->labRTTY->setEnabled (true);
ui_->RTTY_Exchange->setEnabled (true);
} else {
ui_->labRTTY->setEnabled (false);
ui_->RTTY_Exchange->setEnabled (false);
}
if (ui_->cbContestName->isChecked() and !ui_->rbFox->isChecked() and !ui_->rbHound->isChecked()
and !ui_->rbQ65pileup->isChecked() and ui_->gbSpecialOpActivity->isChecked()) {
ui_->labCN->setEnabled (true);
ui_->Contest_Name->setEnabled (true);
} else {
ui_->labCN->setEnabled (false);
ui_->Contest_Name->setEnabled (false);
}
if ((ui_->rbFox->isChecked() or ui_->rbHound->isChecked()) and ui_->gbSpecialOpActivity->isChecked()) {
ui_->cbSuperFox->setEnabled (true);
ui_->cbOTP->setEnabled (true);
} else {
ui_->cbSuperFox->setEnabled (false);
ui_->cbOTP->setEnabled (false);
ui_->cbShowOTP->setEnabled(false);
}
if (!ui_->rbFox->isChecked() and !ui_->rbHound->isChecked() and !ui_->rbQ65pileup->isChecked()
and ui_->gbSpecialOpActivity->isChecked()) {
ui_->cbContestName->setEnabled (true);
} else {
ui_->cbContestName->setEnabled (false);
}
if (!ui_->cbOTP->isChecked() or !ui_->gbSpecialOpActivity->isChecked()) {
ui_->OTPSeed->setEnabled(false);
ui_->OTPUrl->setEnabled(false);
ui_->sbOTPinterval->setEnabled(false);
ui_->lblOTPSeed->setEnabled(false);
ui_->lblOTPUrl->setEnabled(false);
ui_->lblOTPEvery->setEnabled(false);
ui_->cbShowOTP->setEnabled(false);
} else {
if (ui_->rbHound->isChecked()) {
if (ui_->OTPUrl->text().isEmpty())
{
ui_->OTPUrl->setText(FoxVerifier::default_url());
}
ui_->OTPUrl->setEnabled(true);
ui_->lblOTPUrl->setEnabled(true);
ui_->cbShowOTP->setEnabled(true);
} else {
ui_->OTPUrl->setEnabled(false);
ui_->lblOTPUrl->setEnabled(false);
}
if (ui_->rbFox->isChecked()) {
ui_->sbOTPinterval->setEnabled(true);
ui_->OTPSeed->setEnabled(true);
ui_->lblOTPSeed->setEnabled(true);
ui_->lblOTPEvery->setEnabled(true);
ui_->cbShowOTP->setEnabled(false);
} else {
ui_->OTPSeed->setEnabled(false);
ui_->lblOTPSeed->setEnabled(false);
ui_->lblOTPEvery->setEnabled(false);
ui_->sbOTPinterval->setEnabled(false);
}
}
}
void Configuration::impl::on_OTPUrl_textEdited (QString const& url){
auto text = url;
if (text.size() == 0)
{
ui_->OTPUrl->setText(FoxVerifier::default_url());
}
}
void Configuration::impl::on_OTPSeed_textEdited (QString const& url){
ui_->OTPSeed->setText(url.toUpper());
}
void Configuration::impl::on_Field_Day_Exchange_textEdited (QString const& exchange)
{
auto text = exchange.simplified ().toUpper ();

View File

@ -9,7 +9,6 @@
#include "models/IARURegions.hpp"
#include "Audio/AudioDevice.hpp"
#include "Transceiver/Transceiver.hpp"
#include "otpgenerator.h"
#include "pimpl_h.hpp"
@ -138,7 +137,6 @@ public:
bool decode_at_52s () const;
bool single_decode () const;
bool twoPass() const;
bool superFox() const;
bool bFox() const;
bool bHound() const;
bool bLowSidelobes() const;
@ -189,16 +187,10 @@ public:
void setSpecial_Hound();
void setSpecial_Fox();
void setSpecial_None();
void toggle_SF();
bool highlight_DXcall () const;
bool highlight_DXgrid () const;
bool Individual_Contest_Name() const;
bool validate_otp_seed(QString);
QString OTPSeed() const;
QString OTPUrl() const;
bool OTPEnabled() const;
bool ShowOTP() const;
unsigned int OTPinterval() const;
// 0 1 2 3 4 5 6 7 8 9
enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, WW_DIGI, FOX, HOUND, ARRL_DIGI, Q65_PILEUP};
SpecialOperatingActivity special_op_id () const;
@ -233,8 +225,7 @@ public:
// This method queries if a CAT and PTT connection is operational.
bool is_transceiver_online () const;
// Start the rig connection, safe and normal to call when rig is
// already open.
// Start the rig connection, safe and normal to call when rig is already open.
bool transceiver_online ();
// check if a real rig is configured

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>760</width>
<height>648</height>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
@ -1251,7 +1251,7 @@ a few, particularly some Kenwood rigs, require it).</string>
</spacer>
</item>
<item row="10" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_11">
<layout class="QHBoxLayout" name="testCATPTT_Layout">
<item>
<widget class="QPushButton" name="test_CAT_push_button">
<property name="toolTip">
@ -2907,8 +2907,49 @@ Right click for insert and delete options.</string>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_15" columnstretch="1,1,0,2">
<item row="2" column="3">
<layout class="QGridLayout" name="gridLayout_15" columnstretch="1,0,0,0">
<item row="0" column="3">
<widget class="QRadioButton" name="rbHound">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;FT8 DXpedition mode: Hound operator calling the DX.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>Hound</string>
</property>
<property name="text">
<string>Hound</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="rbNA_VHF_Contest">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>NA VHF Contest</string>
</property>
<property name="text">
<string>NA VHF</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="1" column="3">
<layout class="QHBoxLayout" name="horizontalLayout_17" stretch="2,1,1">
<item>
<widget class="QRadioButton" name="rbField_Day">
@ -2977,63 +3018,55 @@ Right click for insert and delete options.</string>
</item>
</layout>
</item>
<item row="1" column="3">
<layout class="QHBoxLayout" name="OTP_Layout_2" stretch="0,0,0,1">
<item>
<widget class="QCheckBox" name="cbShowOTP">
<item row="3" column="3">
<widget class="QRadioButton" name="rbARRL_Digi">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Show OTP messages in the Band Activity window.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL International Digital Contest&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Show OTP messages</string>
</property>
<property name="checked">
<bool>false</bool>
<string>ARRL Digi Contest</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_17">
<item row="0" column="1" rowspan="3">
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblOTPUrl">
<property name="text">
<string>OTP URL:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="OTPUrl">
<item row="3" column="0">
<widget class="QRadioButton" name="rbWW_DIGI">
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
<width>0</width>
<height>18</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;URL used to verify OTP codes.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;World-Wide Digi-mode contest&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>WW Digital Contest</string>
</property>
<property name="text">
<string>https://www.9dx.cc</string>
<string>WW Digi Contest</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<item row="4" column="0">
<widget class="QRadioButton" name="rbQ65pileup">
<property name="minimumSize">
<size>
@ -3052,153 +3085,7 @@ Right click for insert and delete options.</string>
</attribute>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="rbNA_VHF_Contest">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>NA VHF Contest</string>
</property>
<property name="text">
<string>NA VHF</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="3" column="0">
<widget class="QRadioButton" name="rbEU_VHF_Contest">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;European VHF+ contests requiring a signal report, serial number, and 6-character locator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>EU VHF Contest</string>
</property>
<property name="text">
<string>EU VHF Contest</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="cbSuperFox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check this box to transmit (Fox) or receive (Hound) the SuperFox waveform.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>SuperFox mode</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="rbFox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;FT8 DXpedition mode: Fox (DXpedition) operator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>Fox</string>
</property>
<property name="text">
<string>Fox</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="4" column="3">
<widget class="QRadioButton" name="rbARRL_Digi">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;ARRL International Digital Contest&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>ARRL Digi Contest</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="5" column="3">
<layout class="QHBoxLayout" name="horizontalLayout_24">
<item>
<widget class="QCheckBox" name="cbContestName">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Call CQ with an individual contest name instead of TEST, RU, or WW. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>CQ with individual contest name</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_25">
<item>
<widget class="QLabel" name="labCN">
<property name="text">
<string>Contest name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="Contest_Name">
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="maxLength">
<number>4</number>
</property>
<property name="cursorPosition">
<number>0</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item row="3" column="3">
<item row="2" column="3">
<layout class="QHBoxLayout" name="horizontalLayout_18" stretch="2,1,1">
<item>
<widget class="QRadioButton" name="rbRTTY_Roundup">
@ -3267,51 +3154,61 @@ Right click for insert and delete options.</string>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QRadioButton" name="rbWW_DIGI">
<property name="minimumSize">
<size>
<width>0</width>
<height>18</height>
</size>
</property>
<item row="0" column="0">
<widget class="QRadioButton" name="rbFox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;World-Wide Digi-mode contest&lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;FT8 DXpedition mode: Fox (DXpedition) operator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>WW Digital Contest</string>
<string>Fox</string>
</property>
<property name="text">
<string>WW Digi Contest</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="0" column="3">
<layout class="QHBoxLayout" name="horizontalLayout_27" stretch="0,1">
<item>
<widget class="QRadioButton" name="rbHound">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;FT8 DXpedition mode: Hound operator calling the DX.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>Hound</string>
</property>
<property name="text">
<string>Hound</string>
<string>Fox</string>
</property>
<property name="checked">
<bool>true</bool>
<bool>false</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="2" column="0">
<widget class="QRadioButton" name="rbEU_VHF_Contest">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;European VHF+ contests requiring a signal report, serial number, and 6-character locator.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="accessibleName">
<string>EU VHF Contest</string>
</property>
<property name="text">
<string>EU VHF Contest</string>
</property>
<attribute name="buttonGroup">
<string notr="true">special_op_activity_button_group</string>
</attribute>
</widget>
</item>
<item row="4" column="3">
<layout class="QHBoxLayout" name="horizontalLayout_24">
<item>
<spacer name="horizontalSpacer_15">
<widget class="QCheckBox" name="cbContestName">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Call CQ with an individual contest name instead of TEST, RU, or WW. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>CQ with individual contest name</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_12">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
@ -3323,111 +3220,39 @@ Right click for insert and delete options.</string>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_25">
<item>
<widget class="QLabel" name="labCN">
<property name="text">
<string>Contest name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="Contest_Name">
<property name="maximumSize">
<size>
<width>70</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="maxLength">
<number>4</number>
</property>
<property name="cursorPosition">
<number>0</number>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0" colspan="3">
<layout class="QHBoxLayout" name="OTP_Layout" stretch="0,0,0,1,0,0,0,1">
<item>
<widget class="QCheckBox" name="cbOTP">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Click to enable OTP method of Fox verification. Requires internet.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>OTP</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>7</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblOTPSeed">
<property name="text">
<string>Key:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="OTPSeed">
<property name="minimumSize">
<size>
<width>110</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fox's key to generate OTP Codes.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>M2ZUU5CW6EVOY2HU</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_14">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>10</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="lblOTPEvery">
<property name="text">
<string>Interval</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbOTPinterval">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Interval at which the OTP messages are sent. Select 1 to sign every message.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="maximum">
<number>20</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_15">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
@ -3595,8 +3420,13 @@ Right click for insert and delete options.</string>
<tabstop>rbLowSidelobes</tabstop>
<tabstop>rbMaxSensitivity</tabstop>
<tabstop>gbSpecialOpActivity</tabstop>
<tabstop>rbFox</tabstop>
<tabstop>rbHound</tabstop>
<tabstop>rbNA_VHF_Contest</tabstop>
<tabstop>rbField_Day</tabstop>
<tabstop>rbEU_VHF_Contest</tabstop>
<tabstop>rbRTTY_Roundup</tabstop>
<tabstop>rbWW_DIGI</tabstop>
<tabstop>Field_Day_Exchange</tabstop>
<tabstop>RTTY_Exchange</tabstop>
</tabstops>
@ -3669,12 +3499,12 @@ Right click for insert and delete options.</string>
</connections>
<buttongroups>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="special_op_activity_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="PTT_method_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="special_op_activity_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="PTT_method_button_group"/>
</buttongroups>
</ui>

View File

@ -8,7 +8,7 @@ before proceeding.
I recommend that you follow the installation instructions especially if you
are moving from v2.5 to v2.6 or later, of WSJT-X or you have upgraded macOS.
Double-click on the wsjtx-...-Darwin.dmg file you have downloaded from the main web-site.
Double-click on the wsjtx-...-Darwin.dmg file you have downloaded from K1JT's web-site.
Make sure that you leave this window open for the remaining installation steps.
Now open a Terminal window by going to Applications->Utilities and clicking on Terminal.
@ -23,10 +23,6 @@ each line.
you will be asked for your normal password because authorisation is needed to copy this file.
(Your password will not be echoed but press the Return key when completed.)
If your Mac is using Sonoma 14.6 or later then in addition to these two commands you must visit:
System Settings > General > Login Items > sysctl and select ON for sysctl.
IMPORTANT: Now re-boot your Mac otherwise these changes will not take effect.
After the reboot you should re-open the Terminal window as before and you can check
@ -37,18 +33,17 @@ that the change has been made by typing:
If shmmax is not shown as 52428800 then contact me since WSJT-X will fail to load with
an error message: "Unable to create shared memory segment". If the value of shmmax
is shown as 20971520 then it is probable that you have download JTDX. WSJT-X and JTDX
cannot both control the shmmax parameter. Contact me for advice.
cannot both control the shmmax paramter. Contact me for advice.
You can now close the Terminal window. It will not be necessary to repeat this procedure
again, even when you download an updated version of WSJT-X. It might be necessary if you
upgrade macOS.
Drag the WSJT-X app to your preferred location, such as Applications, and close the window.
Drag the WSJT-X app to your preferred location, such as Applications.
You need to configure your sound card. Visit Applications > Utilities > Audio MIDI
Setup and select your sound card and then set Format to be "48000Hz 2ch-16bit" for
input and output. On rare occasions problems with audio output to your rig can be
corrected if you select 44100Hz for output format.
input and output.
Now double-click on the WSJT-X app and two windows will appear. Select Preferences
under the WSJT-X Menu and fill in various station details on the General panel.
@ -124,9 +119,4 @@ on combining multiple audio interfaces which is at https://support.apple.com/en-
In normal circumstances an application which has not been directly accessed for a while can be
subject to App Nap which means it is suspended until such time as its windows are accessed. If
you find that WSJT-X seems disabled check this by opening Applications > Utilities > Activity Monitor and
then select Energy and look at the column marked App Nap. If you see wsjtx marked "Yes" then you need
to disable App Nap by opening a Terminal window and typing:
defaults write NSGlobalDomain NSAppSleepDisabled -bool YES
This will disable App Nap for all applications. If you wish to reverse this type:
defaults delete NSGlobalDomain NSAppSleepDisabled

View File

@ -70,8 +70,7 @@ void Modulator::start (QString mode, unsigned symbolsLength, double framesPerSym
m_bFastMode=fastMode;
m_TRperiod=TRperiod;
unsigned delay_ms=1000;
if((mode=="FT8" and m_nsps==1920) or (mode=="FST4" and m_nsps==720)) delay_ms=500; //FT8, FST4-15
if((mode=="FT8" and m_nsps==1024)) delay_ms=400; //SuperFox Qary Polar Code transmission
if(mode=="FT8" or (mode=="FST4" and m_nsps==720)) delay_ms=500; //FT8, FST4-15
if(mode=="Q65" and m_nsps<=3600) delay_ms=500; //Q65-15 and Q65-30
if(mode=="FT4") delay_ms=300; //FT4

202
NEWS
View File

@ -11,206 +11,6 @@
Copyright 2001 - 2024 by Joe Taylor, K1JT, and the WSJT Development Team
Release: WSJT-X 2.7.0-rc7
September 30, 2024
-------------------------
WSJT-X 2.7.0 Release Candidate 7 brings significant improvements for
the new SuperFox mode. It introduces a new verification system which
replaces the previous one, and works for both the SuperFox mode and
for old-style Fox and Hound operation. All code for SuperFox
operation is now open source.
IMPORTANT: OpenSSL v1.1.1 or higher is required for the real-time
verification of Fox and SuperFox messages.
Enhancements to the SuperFox decoder:
- Performance of the SuperFox decoder has been further improved.
- You can now set individual FTol values and tune the decoder to
the exact sync frequency of the SuperFox signal if it is not exactly
750 Hz. Both result in a better decodability in certain situations.
- Important: The Rx frequency must be set close to the sync frequency
+/- FTol, for example 750 +/- 50 Hz.
Introduction of a new Fox verification system:
- The new Fox verification system uses one time passwords (OTPs), and
works for the SuperFox mode as well as for old-style Fox and Hound
operation. It can be enabled by the new OTP checkbox on the Advanced
tab of the Settings dialog.
- Fox or SuperFox stations send individual OTPs via radio. Hounds
automatically check the validity of the received OTPs in real time
from a server when there is an internet connection. Otherwise, the
validity can also be queried manually later. OTP verifications can
only be retrieved once the transmission has already taken place.
- You may optionally display the received OTP values by checking
the box "Show OTP messages".
- If the Fox or SuperFox callsign is verified by receipt of the
correct OTP, the background color of the Hound or Super Hound label
switches to green.
- Theoretically, DXpeditions can set up their own OTP server, however,
we recommend using the server at https://www.9dx.cc.
- Use of the new Fox verification system requires an OTP key. The
system uses open source code and standard encryption
technology. For testing purposes, non-verified SuperFox
transmissions are now possible without a key.
Improvements to SuperFox/Hound operation:
- SuperHounds must now first decode the SuperFox before they can
call, and a QSO must be started by double-clicking on a SuperFox
decode. (Note that calling the Fox blindly not only leads to
unnecessary band utilization, but can also significantly reduce the
QSO rate due to unanswered (Super)Fox replies.)
- Switching to SuperHound mode automatically sets the Rx frequency to
750 Hz. The previously selected frequency is saved and restored
afterwards.
- Right-clicking on the H button now activates/deactivates SuperFox mode.
- A flaw resulting in sub-optimal SuperFox QSO rates has been
corrected.
- SuperFox decoder now does a more thorough job of rejecting QRM from
non-SuperFox signals.
- Fields in the SuperFox payload not otherwise used in a particular
transmission are now set to known nonzero values. Do NOT use RC6 or
earlier versions to decode SuperFox transmissions from RC7 or
later.
- Old-style Fox stations can now transmit free text messages (up to
13 characters) by using an available stream.
- Some enhancements useful for Fox operators: Active Station Window now
shows band activity. Hound callsigns can be highlighted via UDP API, and
assigned a score for sorting via UDP API. Fox Tx frequency is preserved
when switching in/out of Fox mode.
- UDP Status Update messages now include information on how many callsigns
have highlighting applied, and how many callsigns have a score assigned.
Other enhancements and fixes:
- In FT8 mode, the Settings dialog no longer resets the VFO frequency
to band/mode default unless really needed.
- Several code improvements specifically for macOS.
- Updated CTY.DAT and Hamlib.
Release: WSJT-X 2.7.0-rc6
July 19, 2024
-------------------------
WSJT-X 2.7.0 Release Candidate 6 is a bug-fix release primarily
affecting the new SuperFox mode. The following bugs have been fixed:
- Strong signals from Superfox too frequently failed to decode.
- SuperFox sometimes sent incorrect signal reports and an invalid
digital signature.
- A Fortran bounds error could sometimes occur in the SuperFox
decoder.
- For SuperFox operator, the "age" displayed for Hound callers
became garbled after the 0000 UTC date change.
- Decodes of SuperFox transmissions were not posted to PSK Reporter.
- Some SuperFox-related messages were posted incorrectly to ALL.TXT.
- Logic for turning the SuperHound label green was flawed in some
circumstances.
Release Candidate 6 also includes updates to Hamlib and the Chinese
user interface translation.
Release: WSJT-X 2.7.0-rc5
July 1, 2024
-------------------------
WSJT-X 2.7.0 Release Candidate 5 introduces "SuperFox" mode, a
powerful new tool designed to help DXpeditions make digital QSOs at
very high rates. RC5 also brings several other improvements and bug
fixes.
SuperFox mode:
- The SuperFox mode behaves operationally like the present Fox and
Hounds mode but uses a constant envelope waveform for Fox's
transmissions rather than sending concurrent streams of up to five
normal FT8 signals. This approach means that up to 9 messages can
be transmitted simultaneously with no signal-strength penalty,
resulting in a system gain of about +10 dB compared to the
conventional Fox/Hound operation with 5 slots.
- IMPORTANT: Older revisions of WSJT-X and derivative programs will
not be able to decode SuperFox transmissions. Hounds must use
WSJT-X 2.7.0-rc5 (or a later release, when available) to receive
SuperFox messages.
- Hounds chasing the DX station will transmit normal FT8 signals, as
in the old-style Fox and Hound mode. QSOs will be logged as FT8
mode.
- When using SuperFox mode, Hound stations may call at any frequency
in Fox's received passband, including the range 0 - 1000 Hz.
Hounds do not QSY to a lower frequency for their final
transmission.
- SuperFox Operation requires the Fox operator to use a valid digital
key. Keys will be issued in advance to legitimate DXpeditions by
the Northern California DX Foundation, and will be kept secret.
- Every SuperFox transmission includes a unique digital signature.
Hounds receiving a SuperFox message will see a "<callsign> verified"
flag if the transmitted signature is valid, and the on-screen
"Super Hound" label will turn from red to green.
- Hound operation should begin by selecting "Special operating
activity", "Hound", and "SuperFox mode" on the Settings -> Advanced
tab. Alternatively, right-clicking on the FT8 button toggles
SuperFox mode on/off for either Fox or Hound, allowing quick
transitions between SuperFox and old-style Fox and Hound operation.
- SuperFox stations can send free text messages of up to 26 characters
together with messages to as many as 4 Hounds.
Other enhancements:
- Corrected a flaw that caused "Log automatically" to not work for
the ARRL Digi Contest.
- Control elements for special operating activities are now disabled
(grayed out) if the respective function is not applicable.
- Corrected a longstanding flaw that caused "Start new period
decodes at top" to stop working properly after some time.
- Right-click mouse press events are now less error-prone.
- Improved the readability of the first line when "Start new period
decodes at top" is checked.
- 4-digit grids are now logged for certain contest modes to ensure that
the log complies with contest rules.
- The Fox Tx frequency is now saved and restored separately.
Release: WSJT-X 2.7.0-rc4
March 11, 2024
-------------------------
@ -253,8 +53,6 @@ WSJT-X:
our recommendations) messages with short (10-bit) callsign hashes
are used in standard FT4/FT8 sub-bands.
- Enhancements useful for Fox operators.
Release: WSJT-X 2.7.0-rc3
January 1, 2024
-------------------------

View File

@ -1,125 +0,0 @@
#include "FoxVerifier.hpp"
#include "Logger.hpp"
FoxVerifier::FoxVerifier(QString user_agent, QNetworkAccessManager *manager,QString base_url, QString callsign, QDateTime timestamp, QString code, unsigned int hz=750) : QObject(nullptr)
{
manager_ = manager;
finished_ = false;
errored_ = false;
callsign_ = callsign;
code_ = code;
ts_ = timestamp;
hz_ = hz;
// make sure we URLencode the callsign, for things like E51D/MM
QString encodedCall = QString::fromUtf8(QUrl::toPercentEncoding(callsign));
QString url = QString("%1/check/").arg(base_url) + encodedCall + QString("/%1/%2.text").arg(timestamp.toString(Qt::ISODate)).arg(code);
LOG_INFO(QString("FoxVerifier: url %1").arg(url).toStdString());
q_url_ = QUrl(url);
if (manager_ == nullptr) {
LOG_INFO("FoxVerifier: manager is null, creating new one");
manager_ = new QNetworkAccessManager(this);
manager_->deleteLater();
}
if (q_url_.isValid()) {
request_ = QNetworkRequest(q_url_);
request_.setRawHeader( "User-Agent" , user_agent.toUtf8());
request_.setRawHeader( "Accept" , "*/*" );
request_.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
request_.setTransferTimeout(FOXVERIFIER_DEFAULT_TIMEOUT_MSEC);
#endif
reply_ = manager_->get(request_);
connect(reply_, &QNetworkReply::finished, this, &FoxVerifier::httpFinished);
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
connect(reply_, &QNetworkReply::errorOccurred, this, &FoxVerifier::errorOccurred);
#endif
connect(reply_, &QNetworkReply::redirected, this, &FoxVerifier::httpRedirected);
connect(reply_, &QNetworkReply::encrypted, this, &FoxVerifier::httpEncrypted);
#if QT_CONFIG(ssl)
connect(reply_, &QNetworkReply::sslErrors, this, &FoxVerifier::sslErrors);
#else
LOG_INFO("FoxVerifier: ssl not supported");
#endif
} else {
LOG_INFO(QString("FoxVerifier: url invalid ! %1").arg(url).toStdString());
}
}
FoxVerifier::~FoxVerifier() {
}
bool FoxVerifier::finished() {
return finished_;
}
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
void FoxVerifier::errorOccurred(QNetworkReply::NetworkError code)
{
int status = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString reason = reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
errored_ = true;
error_reason_ = reply_->errorString();
if (reply_->error() != QNetworkReply::NoError) {
LOG_INFO(QString("FoxVerifier: errorOccurred status %1 error [%2][%3] isFinished %4 isrunning %5 code %6").arg(status).arg(
reason).arg(error_reason_).arg(reply_->isFinished()).arg(reply_->isRunning()).arg(code).toStdString());
return;
}
// TODO emit
}
#endif
void FoxVerifier::httpFinished()
{
int status = reply_->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
QString reason = reply_->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString();
if (reply_->error() != QNetworkReply::NoError) {
LOG_INFO(QString("FoxVerifier: httpFinished error:[%1 - %2] msg:[%3]").arg(status).arg(reason).arg(reply_->errorString()).toStdString());
reply_->abort();
emit verifyError(status, ts_, callsign_, code_, hz_, reply_->errorString());
}
return_value = reply_->read(1024); // limit amount we get
LOG_INFO(QString("FoxVerifier: httpFinished status:[%1 - %2] body:[%3] ").arg(status).arg(reason).arg(return_value).toStdString());
finished_ = true;
reply_->deleteLater();
if (status >= 200 && status <= 299) {
emit verifyComplete(status, ts_, callsign_, code_, hz_, return_value);
}
}
void FoxVerifier::sslErrors(const QList<QSslError> &)
{
LOG_INFO(QString("FoxVerifier: sslErrors").toStdString());
reply_->ignoreSslErrors();
}
void FoxVerifier::httpRedirected(const QUrl &url) {
LOG_INFO(QString("FoxVerifier: redirected to %1").arg(url.toString()).toStdString());
}
void FoxVerifier::httpEncrypted() {
LOG_INFO("FoxVerifier: httpEncrypted");
}
QString FoxVerifier::formatDecodeMessage(QDateTime ts, QString callsign, unsigned int hz_, QString const& verify_message) {
//"172100 -00 0.0 750 ~ K8R VERIFIED"
QTime rx_time = ts.time();
QString hz=QString("%1").arg(hz_, 4, 10 ); // insert Hz
if (verify_message.endsWith(" VERIFIED")) {
return QString("%1 0 0.0 %2 ~ %3 verified").arg(rx_time.toString("hhmmss")).arg(hz).arg(callsign);
} else
if (verify_message.endsWith(" INVALID"))
{
return QString("%1 0 0.0 %2 ~ %3 invalid").arg(rx_time.toString("hhmmss")).arg(hz).arg(callsign);
}
else
return QString{};
}
QString FoxVerifier::default_url() {
return QString(FOXVERIFIER_DEFAULT_BASE_URL);
}

View File

@ -1,63 +0,0 @@
#ifndef WSJTX2_FOXVERIFIER_HPP
#define WSJTX2_FOXVERIFIER_HPP
#include <QObject>
#include <QString>
#include <QPointer>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QMutex>
#define FOXVERIFIER_DEFAULT_TIMEOUT_MSEC 5000
#define FOXVERIFIER_DEFAULT_BASE_URL "https://www.9dx.cc"
class FoxVerifier : public QObject {
Q_OBJECT
QMutex mutex_;
public:
explicit FoxVerifier(QString user_agent, QNetworkAccessManager *manager, QString base_url, QString callsign, QDateTime timestamp, QString code, unsigned int);
~FoxVerifier();
QString return_value;
bool finished();
static QString formatDecodeMessage(QDateTime ts, QString callsign, unsigned int hz, QString const& verify_message);
static QString default_url();
private:
QNetworkAccessManager* manager_;
QNetworkReply* reply_;
QNetworkRequest request_;
QUrl q_url_;
bool finished_;
bool errored_;
unsigned int hz_;
QString error_reason_;
QDateTime ts_;
QString callsign_;
QString code_;
private slots:
void httpFinished();
void httpRedirected(const QUrl &url);
void httpEncrypted();
#ifndef QT_NO_SSL
void sslErrors(const QList<QSslError> &);
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
void errorOccurred(QNetworkReply::NetworkError code);
#endif
//signals:
//void results(QString verify_response);
//void error(QString const& reason) const;
public slots:
signals:
void verifyComplete(int status, QDateTime ts, QString callsign, QString code, unsigned int hz, QString const& response);
void verifyError(int status, QDateTime ts, QString callsign, QString code, unsigned int hz, QString const& response);
};
#endif //WSJTX2_FOXVERIFIER_HPP

View File

@ -392,21 +392,6 @@ void MessageClient::impl::parse_message (QByteArray const& msg)
}
break;
case NetworkMessage::AnnotationInfo: {
QByteArray dx_call;
bool sort_order_provided{false};
quint32 sort_order{std::numeric_limits<quint32>::max()};
in >> dx_call >> sort_order_provided >> sort_order;
TRACE_UDP ("External Callsign Info:" << dx_call << "sort_order_provided:" << sort_order_provided
<< "sort_order:" << sort_order);
if (sort_order > 50000) sort_order = 50000;
if (check_status(in) != Fail) {
Q_EMIT
self_->annotation_info(QString::fromUtf8(dx_call), sort_order_provided, sort_order);
}
}
break;
default:
// Ignore
//

View File

@ -123,9 +123,6 @@ public:
, bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call
, QString const& dx_grid, bool generate_messages);
// this signal is emitted if the server has sent information about a callsign
Q_SIGNAL void annotation_info (QString const& dx_call, bool sort_order_provided, quint32 sort_order);
// this signal is emitted when network errors occur or if a host
// lookup fails
Q_SIGNAL void error (QString const&) const;

View File

@ -1,21 +0,0 @@
SOURCES += \
Network/FileDownload.cpp \
Network/FoxVerifier.cpp \
Network/LotWUsers.cpp \
Network/MessageClient.cpp \
Network/NetworkAccessManager.cpp \
Network/NetworkMessage.cpp \
Network/NetworkServerLookup.cpp \
Network/PSKReporter.cpp \
Network/wsprnet.cpp
HEADERS += \
Network/FileDownload.hpp \
Network/FoxVerifier.hpp \
Network/LotWUsers.hpp \
Network/MessageClient.hpp \
Network/NetworkAccessManager.hpp \
Network/NetworkMessage.hpp \
Network/NetworkServerLookup.hpp \
Network/PSKReporter.hpp \
Network/wsprnet.h

View File

@ -462,14 +462,6 @@
* decoding may be impacted. A rough rule of thumb might be too
* limit the number of active highlighting requests to no more
* than 100.
*
* Using a callsign of "CLEARALL!" and anything for the
* color values will clear the internal highlighting data. It will
* NOT remove the highlighting on the screen, however. The exclamation
* symbol is used to avoid accidental clearing of all highlighting
* data via a decoded callsign, since an exclamation symbol is not
* a valid character in a callsign.
*
* The "Highlight last" field allows the sender to request that
* all instances of "Callsign" in the last period only, instead
@ -502,33 +494,7 @@
* fields an empty value implies no change, for the quint32 Rx DF
* and Frequency Tolerance fields the maximum quint32 value
* implies no change. Invalid or unrecognized values will be
* silently ignored. NOTE that if a mode/submode change occurs and
* the current frequency is NOT in the frequency table for that
* mode, a frequency change (to the default frequency for that band
* and mode) may occur.
*
* AnnotationInfo In 16 quint32
* Id (unique key) utf8
* DX Call utf8
* Sort Order Provided bool
* Sort Order quint32
*
* The server may send this message at any time. Sort orders can be used
* for sorting hound callers when in Fox mode. A typical usage is to
* "score" callsigns based on number of bands and/or modes worked using
* an external logging program during a DXpedition, to be able to give
* preference to calls that have not been worked before on any other
* band or mode. An external program can watch decodes from wsjt-x,
* then use this message to annotate the calls with a sort order. The
* hound queue can be displayed by that sort order. *
*
* If 'sort order provided' is true, the message also specifies a numeric
* sort order for the DX call.
*
* Invalid or unrecognized values will be silently ignored. A sort-order of
* ffffffff will remove the sort-order value from the internal table.
* Callsigns without a sort order will be valued at zero for sorting purposes
* in the hound display.
* silently ignored.
*/
#include <QDataStream>
@ -560,7 +526,6 @@ namespace NetworkMessage
HighlightCallsign,
SwitchConfiguration,
Configure,
AnnotationInfo,
maximum_message_type_ // ONLY add new message types
// immediately before here
};

View File

@ -11,206 +11,6 @@
Copyright 2001 - 2024 by Joe Taylor, K1JT, and the WSJT Development Team
Release: WSJT-X 2.7.0-rc7
September 30, 2024
-------------------------
WSJT-X 2.7.0 Release Candidate 7 brings significant improvements for
the new SuperFox mode. It introduces a new verification system which
replaces the previous one, and works for both the SuperFox mode and
for old-style Fox and Hound operation. All code for SuperFox
operation is now open source.
IMPORTANT: OpenSSL v1.1.1 or higher is required for the real-time
verification of Fox and SuperFox messages.
Enhancements to the SuperFox decoder:
- Performance of the SuperFox decoder has been further improved.
- You can now set individual FTol values and tune the decoder to
the exact sync frequency of the SuperFox signal if it is not exactly
750 Hz. Both result in a better decodability in certain situations.
- Important: The Rx frequency must be set close to the sync frequency
+/- FTol, for example 750 +/- 50 Hz.
Introduction of a new Fox verification system:
- The new Fox verification system uses one time passwords (OTPs), and
works for the SuperFox mode as well as for old-style Fox and Hound
operation. It can be enabled by the new OTP checkbox on the Advanced
tab of the Settings dialog.
- Fox or SuperFox stations send individual OTPs via radio. Hounds
automatically check the validity of the received OTPs in real time
from a server when there is an internet connection. Otherwise, the
validity can also be queried manually later. OTP verifications can
only be retrieved once the transmission has already taken place.
- You may optionally display the received OTP values by checking
the box "Show OTP messages".
- If the Fox or SuperFox callsign is verified by receipt of the
correct OTP, the background color of the Hound or Super Hound label
switches to green.
- Theoretically, DXpeditions can set up their own OTP server, however,
we recommend using the server at https://www.9dx.cc.
- Use of the new Fox verification system requires an OTP key. The
system uses open source code and standard encryption
technology. For testing purposes, non-verified SuperFox
transmissions are now possible without a key.
Improvements to SuperFox/Hound operation:
- SuperHounds must now first decode the SuperFox before they can
call, and a QSO must be started by double-clicking on a SuperFox
decode. (Note that calling the Fox blindly not only leads to
unnecessary band utilization, but can also significantly reduce the
QSO rate due to unanswered (Super)Fox replies.)
- Switching to SuperHound mode automatically sets the Rx frequency to
750 Hz. The previously selected frequency is saved and restored
afterwards.
- Right-clicking on the H button now activates/deactivates SuperFox mode.
- A flaw resulting in sub-optimal SuperFox QSO rates has been
corrected.
- SuperFox decoder now does a more thorough job of rejecting QRM from
non-SuperFox signals.
- Fields in the SuperFox payload not otherwise used in a particular
transmission are now set to known nonzero values. Do NOT use RC6 or
earlier versions to decode SuperFox transmissions from RC7 or
later.
- Old-style Fox stations can now transmit free text messages (up to
13 characters) by using an available stream.
- Some enhancements useful for Fox operators: Active Station Window now
shows band activity. Hound callsigns can be highlighted via UDP API, and
assigned a score for sorting via UDP API. Fox Tx frequency is preserved
when switching in/out of Fox mode.
- UDP Status Update messages now include information on how many callsigns
have highlighting applied, and how many callsigns have a score assigned.
Other enhancements and fixes:
- In FT8 mode, the Settings dialog no longer resets the VFO frequency
to band/mode default unless really needed.
- Several code improvements specifically for macOS.
- Updated CTY.DAT and Hamlib.
Release: WSJT-X 2.7.0-rc6
July 19, 2024
-------------------------
WSJT-X 2.7.0 Release Candidate 6 is a bug-fix release primarily
affecting the new SuperFox mode. The following bugs have been fixed:
- Strong signals from Superfox too frequently failed to decode.
- SuperFox sometimes sent incorrect signal reports and an invalid
digital signature.
- A Fortran bounds error could sometimes occur in the SuperFox
decoder.
- For SuperFox operator, the "age" displayed for Hound callers
became garbled after the 0000 UTC date change.
- Decodes of SuperFox transmissions were not posted to PSK Reporter.
- Some SuperFox-related messages were posted incorrectly to ALL.TXT.
- Logic for turning the SuperHound label green was flawed in some
circumstances.
Release Candidate 6 also includes updates to Hamlib and the Chinese
user interface translation.
Release: WSJT-X 2.7.0-rc5
July 1, 2024
-------------------------
WSJT-X 2.7.0 Release Candidate 5 introduces "SuperFox" mode, a
powerful new tool designed to help DXpeditions make digital QSOs at
very high rates. RC5 also brings several other improvements and bug
fixes.
SuperFox mode:
- The SuperFox mode behaves operationally like the present Fox and
Hounds mode but uses a constant envelope waveform for Fox's
transmissions rather than sending concurrent streams of up to five
normal FT8 signals. This approach means that up to 9 messages can
be transmitted simultaneously with no signal-strength penalty,
resulting in a system gain of about +10 dB compared to the
conventional Fox/Hound operation with 5 slots.
- IMPORTANT: Older revisions of WSJT-X and derivative programs will
not be able to decode SuperFox transmissions. Hounds must use
WSJT-X 2.7.0-rc5 (or a later release, when available) to receive
SuperFox messages.
- Hounds chasing the DX station will transmit normal FT8 signals, as
in the old-style Fox and Hound mode. QSOs will be logged as FT8
mode.
- When using SuperFox mode, Hound stations may call at any frequency
in Fox's received passband, including the range 0 - 1000 Hz.
Hounds do not QSY to a lower frequency for their final
transmission.
- SuperFox Operation requires the Fox operator to use a valid digital
key. Keys will be issued in advance to legitimate DXpeditions by
the Northern California DX Foundation, and will be kept secret.
- Every SuperFox transmission includes a unique digital signature.
Hounds receiving a SuperFox message will see a "<callsign> verified"
flag if the transmitted signature is valid, and the on-screen
"Super Hound" label will turn from red to green.
- Hound operation should begin by selecting "Special operating
activity", "Hound", and "SuperFox mode" on the Settings -> Advanced
tab. Alternatively, right-clicking on the FT8 button toggles
SuperFox mode on/off for either Fox or Hound, allowing quick
transitions between SuperFox and old-style Fox and Hound operation.
- SuperFox stations can send free text messages of up to 26 characters
together with messages to as many as 4 Hounds.
Other enhancements:
- Corrected a flaw that caused "Log automatically" to not work for
the ARRL Digi Contest.
- Control elements for special operating activities are now disabled
(grayed out) if the respective function is not applicable.
- Corrected a longstanding flaw that caused "Start new period
decodes at top" to stop working properly after some time.
- Right-click mouse press events are now less error-prone.
- Improved the readability of the first line when "Start new period
decodes at top" is checked.
- 4-digit grids are now logged for certain contest modes to ensure that
the log complies with contest rules.
- The Fox Tx frequency is now saved and restored separately.
Release: WSJT-X 2.7.0-rc4
March 11, 2024
-------------------------
@ -253,9 +53,6 @@ WSJT-X:
our recommendations) messages with short (10-bit) callsign hashes
are used in standard FT4/FT8 sub-bands.
- Enhancements useful for Fox operators.
Release: WSJT-X 2.7.0-rc3
January 1, 2024
-------------------------

View File

@ -619,12 +619,6 @@ int HamlibTransceiver::do_start ()
CAT_TRACE ("starting: " << rig_get_caps_cptr (m_->model_, RIG_CAPS_MFG_NAME_CPTR)
<< ": " << rig_get_caps_cptr (m_->model_, RIG_CAPS_MODEL_NAME_CPTR));
token_t token = rig_token_lookup (m_->rig_.data (), "client");
if (RIG_CONF_END != token) // only set if valid for rig model
{
rig_set_conf (m_->rig_.data (), token, "WSJTX");
}
m_->error_check (rig_open (m_->rig_.data ()), tr ("opening connection to rig"));
// reset dynamic state

View File

@ -64,9 +64,6 @@ typedef struct dec_data {
char mygrid[6];
char hiscall[12];
char hisgrid[6];
bool b_even_seq;
bool b_superfox;
int yymmdd;
} params;
} dec_data_t;
@ -94,9 +91,6 @@ extern struct {
int i3bit[5];
char cmsg[5][40];
char mycall[12];
char textMsg[26];
bool bMoreCQs;
bool bSendMsg;
} foxcom_;
#ifdef __cplusplus

3751
cty.dat

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,6 @@ FT8 11101000010011100001000010011000100000
FT8/VHF 11101000010011100001000010011000100000
FT8/Fox 11101000010011100001000000000010000000
FT8/Hound 11101000010011100001000000000011000000
FT8/SupHou 11111000010011100001000000000011000000
-------------------------------------------------
1 2 3
01234567890123456789012345678901234567

View File

@ -29,8 +29,8 @@ the following copyright notice prominently:
*The algorithms, source code, look-and-feel of _{prog}_ and related
programs, and protocol specifications for the modes FSK441, FST4,
FST4W, FT4, FT8, JT4, JT6M, JT9, JT44, JT65, JTMS, Q65, QRA64, ISCAT,
and MSK144 are Copyright (C) 2001-2024 by one or more of the following
and MSK144 are Copyright (C) 2001-2021 by one or more of the following
authors: Joseph Taylor, K1JT; Bill Somerville, G4WJS; Steven Franke,
K9AN; Nico Palermo, IV3NWV; Uwe Risse, DG2YCB; Brian Moran, N9ADG;
Greg Beam, KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; Philip
Karn, KA9Q; and other members of the WSJT Development Group.*
K9AN; Nico Palermo, IV3NWV; Greg Beam, KI7MT; Michael Black, W9MDB;
Edson Pereira, PY2SDR; Philip Karn, KA9Q; and other members of the
WSJT Development Group.*

View File

@ -94,8 +94,8 @@ d). Edit lines as needed. Keeping them in alphabetic order help see dupes.
:sourceforge-jtsdk: https://sourceforge.net/projects/jtsdk[SourceForge JTSDK]
:ubuntu_sdk: https://launchpad.net/~ubuntu-sdk-team/+archive/ppa[Ubuntu SDK Notice]
:win_openssl_packages: https://slproweb.com/products/Win32OpenSSL.html[Windows OpenSSL Packages]
:win32_openssl: https://sourceforge.net/projects/wsjt-x-improved/files/Additional%20Files/OpenSSL/Win32OpenSSL_Light-1_1_1a.msi/download[Win32 OpenSSL Light Package]
:win64_openssl: https://sourceforge.net/projects/wsjt-x-improved/files/Additional%20Files/OpenSSL/Win64OpenSSL_Light-1_1_1a.msi[Win64 OpenSSL Light Package]
:win32_openssl: https://slproweb.com/download/Win32OpenSSL_Light-1_1_1s.msi[Win32 OpenSSL Light Package]
:win64_openssl: https://slproweb.com/download/Win64OpenSSL_Light-1_1_1s.msi[Win64 OpenSSL Light Package]
:writelog: https://writelog.com/[Writelog]
:wsjtx_group: https://groups.io/g/wsjtgroup[WSJT GROUP User Forum]
:wsjtx_group2: https://groups.io/g/wsjtgroup/join[join the group]

View File

@ -4,10 +4,8 @@ Download and execute the package file {win32} (Windows 7 or later,
32-bit) or {win64} (Windows 7 or later, 64-bit) following these
instructions:
* Install _WSJT-X_ into its own directory, for example
`C:\WSJTX` or `C:\WSJT\WSJTX`, rather than the conventional location
`C:\Program Files ...\WSJTX`. Do not use a directory path that
includes an embedded blank.
* Install _WSJT-X_ into its own directory, for example `C:\WSJTX` or `C:\WSJT\WSJTX`, rather than the conventional location `C:\Program
Files ...\WSJTX`.
* All program files relating to _WSJT-X_ are stored in the chosen
installation directory and its subdirectories.

View File

@ -1,12 +1,11 @@
[[NEW_FEATURES]]
=== New in Version {VERSION_MAJOR}.{VERSION_MINOR}
_WSJT-X 2.7_ introduces a new program called *QMAP*, new Special
Operating Activities *Q65 Pileup* and *SuperFox mode*, an option to
*Update Hamlib* at the click of a button, and a number of other
enhancements and bug fixes.
_WSJT-X 2.7_ introduces a new program called *QMAP*, a new Special
Operating Activity *Q65 Pileup*, an option to *Update Hamlib* at the
click of a button, and a number of other enhancements and bug fixes.
- *QMAP* and *Q65 Pileup* mode are of particular interest to those engaged
- QMAP and Q65 Pileup mode are of particular interest to those engaged
in Earth-Moon-Earth (EME) communication, but other applications may
be found for them as well. QMAP is currently available for Windows
only; it is derived from MAP65, an older program used since 2007 for
@ -20,15 +19,6 @@ enhancements and bug fixes.
Quick-Start guide posted here:
https://wsjt.sourceforge.io/Quick_Start_WSJT-X_2.7_QMAP.pdf
- *SuperFox mode* behaves operationally like the old-style Fox and
Hounds mode but uses a new constant envelope waveform for Fox's
transmissions. Messages can be transmitted simultaneously to as many
as 9 Hounds with no signal-strength penalty, resulting in a system
gain of about +10 dB compared to the older Fox-and-Hound operation
with 5 slots. Further details on SuperFox mode can be found in the
Quick-Start guide posted here:
https://wsjt.sourceforge.io/SuperFox_User_Guide.pdf
- A button *Update Hamlib* now appears on the *Settings -> Radio* tab.
On Windows it allows the user to automatically download and install
the latest version of the rig-control features in Hamlib. The

View File

@ -330,7 +330,7 @@ comparable to tone spacing.
[width="100%",cols="h,5*^",frame=topbot,options="header"]
|===
|T/R Period (s) |A Spacing Width (Hz)|B Spacing Width (Hz)|C Spacing Width (Hz)|D Spacing Width (Hz)|E Spacing Width (Hz)
|15|6.67 &#160; &#160; 433|13.33 &#160; &#160; 867|26.67 &#160; &#160; 1733|N/A|N/A
|15|6.67 &#160; &#160; 4.33|13.33 &#160; &#160; 867|26.67 &#160; &#160; 1733|N/A|N/A
|30|3.33 &#160; &#160; 217|6.67 &#160; &#160; 433|13.33 &#160; &#160; 867| 26.67 &#160; &#160; 1733| N/A
|60|1.67 &#160; &#160; 108|3.33 &#160; &#160; 217|6.67 &#160; &#160; 433|13.33 &#160; &#160; 867|26.67 &#160; &#160; 1733
|120|0.75 &#160; &#160; 49|1.50 &#160; &#160; 98|3.00 &#160; &#160; 195|6.00 &#160; &#160; 390| 12.00 &#160; &#160; 780

View File

@ -1,235 +0,0 @@
program cwsim
! Generate simulated audio for a CW message sent repeatedly for 60 seconds
use wavhdr
parameter (NMAX=60*12000)
type(hdr) h !Header for the .wav file
integer*2 iwave(NMAX) !Generated waveform (no noise)
integer icw(500) !Encoded CW message bits
complex cspread(0:NMAX-1) !Complex amplitude for Rayleigh fading
complex cdat(0:NMAX-1) !Complex waveform
real dat(NMAX) !Audio waveform
real*4 xnoise(NMAX) !Generated random noise
character*60 message
character*12 arg
nargs=iargc()
if(nargs.ne.6) then
print*,'Usage: cwsim "message" freq bw wpm fspread snr'
print*,'Example: cwsim "CQ CQ CQ DE K1JT K1JT K1JT" 700 100 20 100 -10'
go to 999
endif
call getarg(1,message)
call getarg(2,arg)
read(arg,*) ifreq !Audio frequency (Hz)
call getarg(3,arg)
read(arg,*) bw !Bandwidth (Hz)
call getarg(4,arg)
read(arg,*) wpm !CW speed, words per minute
call getarg(5,arg)
read(arg,*) fspread !Doppler spread in Hz
call getarg(6,arg)
read(arg,*) snrdb !S/N in dB (2500 hz reference BW)
rms=500.0
bandwidth_ratio=2500.0/6000.0
sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snrdb)
twopi=8.0*atan(1.0)
h=default_header(12000,NMAX)
open(10,file='000000_0000.wav',access='stream',status='unknown')
do i=1,NMAX !Generate gaussian noise
xnoise(i)=gran()
enddo
itone=0
call morse(message,icw,ncw)
call cwsig(icw,ncw,ifreq,wpm,sig,cdat)
nfft=NMAX
if(fspread.ne.0) then !Apply specified Doppler spread
nh=nfft/2
df=12000.0/nfft
cspread(0)=1.0
cspread(nh)=0.
b=6.0 !Use truncated Lorenzian shape for fspread
do i=1,nh
f=i*df
x=b*f/fspread
z=0.
a=0.
if(x.lt.3.0) then !Cutoff beyond x=3
a=sqrt(1.111/(1.0+x*x)-0.1) !Lorentzian amplitude
phi1=twopi*rran() !Random phase
z=a*cmplx(cos(phi1),sin(phi1))
endif
cspread(i)=z
z=0.
if(x.lt.3.0) then !Same thing for negative freqs
phi2=twopi*rran()
z=a*cmplx(cos(phi2),sin(phi2))
endif
cspread(nfft-i)=z
enddo
call four2a(cspread,nfft,1,1,1) !Transform to time domain
sum=0.
do i=0,nfft-1
p=real(cspread(i))**2 + aimag(cspread(i))**2
sum=sum+p
enddo
avep=sum/nfft
fac=sqrt(1.0/avep)
cspread=fac*cspread !Normalize to constant avg power
cdat=cspread*cdat !Apply Rayleigh fading
endif
dat=aimag(cdat) + xnoise
cdat=dat
call four2a(cdat,nfft,1,-1,1) !c2c to frequency domain
ia=max(250/df,(ifreq-0.5*bw)/df)
ib=ia+bw/df
cdat(0:ia)=0.
cdat(ib:)=0.
call four2a(cdat,nfft,1,+1,1) !c2c to time domain
fac=sqrt(5000/bw)/nfft
dat=fac*real(cdat)
iwave=nint(rms*dat)
write(10) h,iwave
close(10)
999 end program cwsim
subroutine cwsig(icw,ncw,ifreq,wpm,sig,cdat)
parameter(NMAX=60*12000)
integer icw(ncw)
complex cdat(NMAX)
complex z(NMAX)
real x(NMAX)
real y(NMAX)
real*8 dt,twopi,phi,dphi,fsample,tdit,t
nspd=nint(1.2*12000.0/wpm)
fsample=12000.d0 !Sample rate (Hz)
dt=1.d0/fsample !Sample interval (s)
tdit=nspd*dt
twopi=8.d0*atan(1.d0)
dphi=twopi*ifreq*dt
phi=0.
k=12000 !Start audio at t = 1.0 s
t=0.
npts=59*12000
x=0.
do i=1,npts
t=t+dt
j=nint(t/tdit) + 1
j=mod(j-1,ncw) + 1
phi=phi + dphi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
k=k+1
x(k)=icw(j)
z(k)=cmplx(cos(xphi),sin(xphi))
if(t.ge.59.5) exit
enddo
nadd=0.004/dt
call smo(x,npts,y,nadd)
y=y/nadd
cdat=sig*y*z
return
end subroutine cwsig
subroutine morse(msg,idat,n)
! Convert ascii message to a Morse code bit string.
! Dash = 3 dots
! Space between dots, dashes = 1 dot
! Space between letters = 3 dots
! Space between words = 7 dots
character*(*) msg
integer idat(500)
integer*1 ic(21,38)
data ic/ &
1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,20, &
1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,18, &
1,0,1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,16, &
1,0,1,0,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,14, &
1,0,1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,12, &
1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
1,1,1,0,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,12, &
1,1,1,0,1,1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,14, &
1,1,1,0,1,1,1,0,1,1,1,0,1,0,1,0,0,0,0,0,16, &
1,1,1,0,1,1,1,0,1,1,1,0,1,1,1,0,1,0,0,0,18, &
1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 6, &
1,1,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
1,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,12, &
1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2, &
1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
1,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
1,0,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 4, &
1,0,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,14, &
1,1,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,10, &
1,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,10, &
1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 6, &
1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,12, &
1,0,1,1,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,12, &
1,1,1,0,1,1,1,0,1,0,1,1,1,0,0,0,0,0,0,0,14, &
1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 6, &
1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 4, &
1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0, 8, &
1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,10, &
1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,10, &
1,1,1,0,1,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0,12, &
1,1,1,0,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,14, &
1,1,1,0,1,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,12, &
1,1,1,0,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,14, &
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 2/ !Incremental word space
save
msglen=len(trim(msg))
idat=0
n=6
do k=1,msglen
jj=ichar(msg(k:k))
if(jj.ge.97 .and. jj.le.122) jj=jj-32 !Convert lower to upper case
if(jj.ge.48 .and. jj.le.57) j=jj-48 !Numbers
if(jj.ge.65 .and. jj.le.90) j=jj-55 !Letters
if(jj.eq.47) j=36 !Slash (/)
if(jj.eq.32) j=37 !Word space
j=j+1
! Insert this character
nmax=ic(21,j)
if (n + nmax + 4 .gt. size (idat)) exit
do i=1,nmax
n=n+1
idat(n)=ic(i,j)
enddo
! Insert character space of 2 dit lengths:
n=n+1
idat(n)=0
n=n+1
idat(n)=0
enddo
! Insert word space at end of message
do j=1,4
n=n+1
idat(n)=0
enddo
return
end subroutine morse

View File

@ -67,7 +67,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
ntr0=params%ntr
rms=sqrt(dot_product(float(id2(1:180000)), &
float(id2(1:180000)))/180000.0)
if(rms.lt.0.5) go to 800
if(rms.lt.3.0) go to 800
!cast C character arrays to Fortran character strings
datetime=transfer(params%datetime, datetime)
@ -124,7 +124,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
if(params%nmode.eq.8) then
! We're in FT8 mode
if(ncontest.eq.6) then !Fox=6, Hound=7
if(ncontest.eq.6) then
! Fox mode: initialize and open houndcallers.txt
inquire(file=trim(temp_dir)//'/houndcallers.txt',exist=ex)
if(.not.ex) then
@ -139,11 +140,6 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
open(19,file=trim(temp_dir)//'/houndcallers.txt',status='unknown')
endif
if(ncontest.eq.7 .and. params%b_superfox .and. params%b_even_seq) then
if(params%nzhsym.lt.50) go to 800
! Call the superFox decoder
call sfrx_sub(params%yymmdd,params%nutc,params%nfqso,params%ntol,id2)
else
call timer('decft8 ',0)
newdat=params%newdat
if(params%emedelay.ne.0.0) then
@ -157,18 +153,14 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
logical(params%lapcqonly),params%napwid,mycall,hiscall, &
params%ndiskdat)
call timer('decft8 ',1)
if(nfox.gt.0) then
n30min=minval(n30fox(1:nfox))
n30max=maxval(n30fox(1:nfox))
endif
j=0
if(ncontest.eq.6) then
! Fox mode: save decoded Hound calls for possible selection by FoxOp
n=params%nutc
n30=(3600*(n/10000) + 60*mod((n/100),100) + mod(n,100))/30
if(n30.lt.n30z) nwrap=nwrap+2880 !New UTC day, handle the wrap
n30z=n30
n30=n30+nwrap
rewind 19
if(nfox.eq.0) then
endfile 19
@ -176,23 +168,21 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
else
do i=1,nfox
n=n30fox(i)
nage=min(99,mod(n30-n+288000,2880))
if(nage.le.4) then
if(n30max-n30fox(i).le.4) then
j=j+1
c2fox(j)=c2fox(i)
g2fox(j)=g2fox(i)
nsnrfox(j)=nsnrfox(i)
nfreqfox(j)=nfreqfox(i)
n30fox(j)=n
! nage=min(99,mod(n30-n+288000,2880))
m=n30max-n
if(len(trim(g2fox(j))).eq.4) then
call azdist(mygrid,g2fox(j)//' ',0.d0,nAz,nEl,nDmiles, &
nDkm,nHotAz,nHotABetter)
else
nDkm=9999
endif
write(19,1004) c2fox(j),g2fox(j),nsnrfox(j),nfreqfox(j), &
nDkm,nage
write(19,1004) c2fox(j),g2fox(j),nsnrfox(j),nfreqfox(j),nDkm,m
1004 format(a12,1x,a4,i5,i6,i7,i3)
endif
enddo
@ -671,10 +661,10 @@ contains
endif
b1=i3-i2.eq.5 .and. isgrid4(g2)
b2=i3-i2.eq.1
if(b0 .and. (b1.or.b2) .and. (nint(freq).ge.1000 .or. params%b_superfox)) then
if(b0 .and. (b1.or.b2) .and. nint(freq).ge.1000) then
n=params%nutc
n30=(3600*(n/10000) + 60*mod((n/100),100) + mod(n,100))/30
if(n30.lt.n30z) nwrap=nwrap+2880 !New UTC day, handle the wrap
if(n30.lt.n30z) nwrap=nwrap+5760 !New UTC day, handle the wrap
n30z=n30
n30=n30+nwrap
if(nfox.lt.MAXFOX) nfox=nfox+1

View File

@ -26,7 +26,7 @@ program ft4code
'LDPC(174,91) encoding,'
print*,'bit and symbol ordering, and other details of the FT4 protocol.'
print*
print*,'Usage: ft4code "message" # Results for specified message'
print*,'Usage: ft4code [-c grid] "message" # Results for specified message'
print*,' ft4code -t # Examples of all message types'
go to 999
endif

View File

@ -1,4 +1,4 @@
subroutine foxgen(bSuperFox,fname)
subroutine foxgen()
! Called from MainWindow::foxTxSequencer() to generate the Tx waveform in
! FT8 Fox mode. The Tx message can contain up to 5 "slots", each carrying
@ -15,12 +15,9 @@ subroutine foxgen(bSuperFox,fname)
! common block.
parameter (NN=79,ND=58,NSPS=4*1920)
parameter (NWAVE=(160+2)*134400*4) !the biggest waveform we generate (FST4-1800 at 48kHz)
parameter (NWAVE=(160+2)*134400*4) ! the biggest waveform we generate (FST4-1800 at 48kHz)
parameter (NFFT=614400,NH=NFFT/2)
logical*1 bSuperFox,bMoreCQs,bSendMsg
character*(*) fname
character*40 cmsg,cmsg2
character*26 textMsg
character*40 cmsg
character*37 msg,msgsent
integer itone(79)
integer*1 msgbits(77),msgbits2
@ -28,26 +25,10 @@ subroutine foxgen(bSuperFox,fname)
real x(NFFT)
real*8 dt,twopi,f0,fstep,dfreq,phi,dphi
complex cx(0:NH)
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall(12), &
textMsg,bMoreCQs,bSendMsg
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall(12)
common/foxcom2/itone2(NN),msgbits2(77)
common/foxcom3/nslots2,cmsg2(5),itone3(151)
equivalence (x,cx),(y,cy)
if(bSuperFox) then
n=nslots
if(bMoreCQs) cmsg(1)(40:40)='1' !Set flag to include a CQ
if(bSendMsg) then
n=min(nslots+1,3)
cmsg(n)=textMsg
cmsg(n)(39:39)='1' !Set flag for text message
nslots=n
endif
nslots2=nslots
cmsg2=cmsg
go to 999
endif
fstep=60.d0
dfreq=6.25d0
dt=1.d0/48000.d0
@ -85,7 +66,7 @@ subroutine foxgen(bSuperFox,fname)
peak3=maxval(abs(wave))
wave=wave/peak3
999 return
return
end subroutine foxgen
! include 'plotspec.f90'

View File

@ -2,12 +2,12 @@ subroutine foxgen_wrap(msg40,msgbits,itone)
parameter (NN=79,ND=58,KK=77,NSPS=4*1920)
parameter (NWAVE=(160+2)*134400*4) !the biggest waveform we generate (FST4-1800)
logical*1 bMoreCQs
character*40 msg40,cmsg
character*12 mycall12
integer*1 msgbits(KK),msgbits2
integer itone(NN)
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall12,bMoreCQs
common/foxcom/wave(NWAVE),nslots,nfreq,i3bit(5),cmsg(5),mycall12
common/foxcom2/itone2(NN),msgbits2(KK)
nslots=1

View File

@ -1,6 +1,6 @@
module ft8_a7
parameter(MAXDEC=200)
parameter(MAXDEC=100)
! For the following three arrays
! First index i=decode number in this sequence
@ -43,7 +43,7 @@ subroutine ft8_a7_save(nutc,dt,f,msg)
! Add this decode to current table for this sequence
ndec(j,1)=ndec(j,1)+1 !Number of decodes in this sequence
i=ndec(j,1) !i is index of a new table entry
if(i.gt.MAXDEC) return !Prevent table overflow (indexes start at 1)
if(i.ge.MAXDEC-1) return !Prevent table overflow
dt0(i,j,1)=dt !Save dt in table
f0(i,j,1)=f !Save f in table

View File

@ -8,10 +8,10 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
logical newdat,first
complex c1(0:NFFT2-1)
complex cx(0:NFFT1/2)
real dd(NMAX),x(NFFT1+2),taper(0:100)
data first/.true./
save x,cx,first,taper
real dd(NMAX),x(NFFT1),taper(0:100)
equivalence (x,cx)
data first/.true./
save cx,first,taper
if(first) then
pi=4.0*atan(1.0)
@ -23,10 +23,11 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
if(newdat) then
! Data in dd have changed, recompute the long FFT
x(1:NMAX)=dd
x(NMAX+1:NFFT1+2)=0. !Zero-pad the x array
x(NMAX+1:NFFT1)=0. !Zero-pad the x array
call four2a(cx,NFFT1,1,-1,0) !r2c FFT to freq domain
newdat=.false.
endif
df=12000.0/NFFT1
baud=12000.0/NSPS
i0=nint(f0/df)

View File

@ -23,7 +23,7 @@ program ft8code
'LDPC(174,91) encoding,'
print*,'bit and symbol ordering, and other details of the FT8 protocol.'
print*
print*,'Usage: ft8code "message" # Results for specified message'
print*,'Usage: ft8code [-c grid] "message" # Results for specified message'
print*,' ft8code -T # Examples of all message types'
print*,' ft8code -t # Short format examples'
go to 999

View File

@ -42,7 +42,7 @@ program ft8d
j2=index(infile,'.wav')
read(infile(j2-6:j2-1),*) nutc
datetime=infile(j2-13:j2-1)
call sync8(iwave,NMAX,nfa,nfb,nfqso,s,candidate,ncand)
call sync8(iwave,nfa,nfb,nfqso,s,candidate,ncand)
syncmin=2.0
dd=iwave
do icand=1,ncand

View File

@ -102,23 +102,13 @@ program ft8sim_gfsk
peak=maxval(abs(wave))
nslots=1
psig=0.
pnoise=0.
if(snrdb.lt.90) then
do i=1,NMAX !Add gaussian noise at specified SNR
xnoise=gran()
if(i.ge.6001 .and. i.le.157692) then
psig=psig + wave(i)*wave(i) !Signal power
pnoise=pnoise + xnoise*xnoise !Noise power in signal interval
endif
wave(i)=wave(i) + xnoise
enddo
endif
! Noise power in signal interval and 2500 Hz bandwidth:
pnoise=bandwidth_ratio*pnoise
snr_2500=db(psig/pnoise) !SNR in 2500 Hz bandwidth
gain=100.0
if(snrdb.lt.90.0) then
wave=gain*wave
@ -135,7 +125,7 @@ program ft8sim_gfsk
open(10,file=fname,status='unknown',access='stream')
write(10) h,iwave !Save to *.wav file
close(10)
write(*,1110) ifile,xdt,f0,snrdb,fname,snr_2500
1110 format(i4,f7.2,f8.2,f7.1,2x,a17,f8.2)
write(*,1110) ifile,xdt,f0,snrdb,fname
1110 format(i4,f7.2,f8.2,f7.1,2x,a17)
enddo
999 end program ft8sim_gfsk

View File

@ -1,4 +1,4 @@
subroutine sync8(dd,npts,nfa,nfb,syncmin,nfqso,maxcand,candidate,ncand,sbase)
subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,candidate,ncand,sbase)
include 'ft8_params.f90'
parameter (MAXPRECAND=1000)
@ -9,13 +9,13 @@ subroutine sync8(dd,npts,nfa,nfb,syncmin,nfqso,maxcand,candidate,ncand,sbase)
real s(NH1,NHSYM)
real savg(NH1)
real sbase(NH1)
real x(NFFT1+2)
real x(NFFT1)
real sync2d(NH1,-JZ:JZ)
real red(NH1)
real red2(NH1)
real candidate0(3,MAXPRECAND)
real candidate(3,maxcand)
real dd(npts)
real dd(NMAX)
integer jpeak(NH1)
integer jpeak2(NH1)
integer indx(NH1)

View File

@ -24,7 +24,7 @@ subroutine watterson(c,npts,nsig,fs,delay,fspread)
do i=0,npts-1
f=i*df
if(i.gt.npts/2) f=(i-npts)*df
x=(f/fspread)**2
x=(f/(0.5*fspread))**2
a=0.
if(x.le.50.0) then
a=exp(-x)

View File

@ -44,23 +44,23 @@ contains
class(ft8_decoder), intent(inout) :: this
procedure(ft8_decode_callback) :: callback
parameter (MAXCAND=600,MAX_EARLY=200,NPTS=15*12000)
parameter (MAXCAND=600,MAX_EARLY=100)
real*8 tsec,tseq
real sbase(NH1)
real candidate(3,MAXCAND)
real dd(NPTS),dd1(NPTS)
real dd(15*12000),dd1(15*12000)
logical, intent(in) :: lft8apon,lapcqonly,nagain
logical newdat,lsubtract,ldupe,lrefinedt
logical*1 ldiskdat
logical lsubtracted(MAX_EARLY)
character*12 mycall12,hiscall12,call_1,call_2
character*4 grid4
integer*2 iwave(NPTS)
integer*2 iwave(15*12000)
integer apsym2(58),aph10(10)
character datetime*13,msg37*37
character*37 allmessages(MAX_EARLY)
character*37 allmessages(200)
character*12 ctime
integer allsnrs(MAX_EARLY)
integer allsnrs(200)
integer itone(NN)
integer itone_save(NN,MAX_EARLY)
real f1_save(MAX_EARLY)
@ -192,7 +192,7 @@ contains
endif
call timer('sync8 ',0)
maxc=MAXCAND
call sync8(dd,NPTS,ifa,ifb,syncmin,nfqso,maxc,candidate,ncand,sbase)
call sync8(dd,ifa,ifb,syncmin,nfqso,maxc,candidate,ncand,sbase)
call timer('sync8 ',1)
do icand=1,ncand
sync=candidate(3,icand)
@ -215,9 +215,6 @@ contains
if(msg37.eq.allmessages(id)) ldupe=.true.
enddo
if(.not.ldupe) then
if(ndecodes.ge.MAX_EARLY) then
cycle
endif
ndecodes=ndecodes+1
allmessages(ndecodes)=msg37
allsnrs(ndecodes)=nsnr

View File

@ -19,10 +19,9 @@ subroutine hspec(id2,k,nutc0,ntrpdepth,nrxfreq,ntol,bmsk144, &
! jh index of most recent data in green(), s()
parameter (JZ=703)
character*(*) line1
character*80 line0
character*80 line1
character*(*) datadir
character*(*) mycall,hiscall
character*12 mycall,hiscall
integer*2 id2(0:120*12000-1)
logical*1 bmsk144,bshmsg,btrain,bswl
real green(0:JZ-1)
@ -97,12 +96,7 @@ subroutine hspec(id2,k,nutc0,ntrpdepth,nrxfreq,ntol,bmsk144, &
tt2=sum(float(abs(id2(k0:k0+3583))))
if(tt1.ne.0.0 .and. tt2.ne.0) then
call mskrtd(id2(k-7168+1:k),nutc0,tsec,ntol,nrxfreq,ndepth, &
mycall,hiscall,bshmsg,btrain,pcoeffs,bswl,datadir,line0)
if(line0(1:1).eq.char(0)) then
line1(1:1)=char(0)
else
line1(1:62)=line0(1:62)
endif
mycall,hiscall,bshmsg,btrain,pcoeffs,bswl,datadir,line1)
endif
endif
endif

View File

@ -47,9 +47,6 @@
character(kind=c_char) :: mygrid(6)
character(kind=c_char) :: hiscall(12)
character(kind=c_char) :: hisgrid(6)
logical(c_bool) :: b_even_seq
logical(c_bool) :: b_superfox
integer(c_int) :: yymmdd
end type params_block
type, bind(C) :: dec_data

View File

@ -16,8 +16,8 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,hiscall, &
character*4 decsym !"&" for mskspd or "^" for long averages
character*37 msgreceived !Decoded message
character*37 msglast,msglastswl !Used for dupechecking
character*(*) line !Formatted line with UTC dB T Freq Msg
character*(*) mycall,hiscall
character*80 line !Formatted line with UTC dB T Freq Msg
character*12 mycall,hiscall
character*37 recent_shmsgs(NSHMEM)
character*(*) datadir
@ -70,19 +70,15 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,hiscall, &
msglastswl=' '
nsnrlast=-99
nsnrlastswl=-99
! mycall13=mycall//' '
! dxcall13=hiscall//' '
mycall13=' '
dxcall13=' '
mycall13(1:12)=mycall(1:12)
dxcall13(1:12)=hiscall(1:12)
mycall13=mycall//' '
dxcall13=hiscall//' '
first=.false.
endif
fc=nrxfreq
! Reset if mycall or dxcall changes
if(mycall13(1:12).ne.mycall(1:12) .or. dxcall13(1:12).ne.hiscall(1:12)) first=.true.
if(mycall13(1:12).ne.mycall .or. dxcall13(1:12).ne.hiscall) first=.true.
! Dupe checking setup
if(nutc00.ne.nutc0 .or. tsec.lt.tsec0) then ! reset dupe checker
@ -94,7 +90,7 @@ subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,hiscall, &
endif
tframe=float(NSPM)/12000.0
line(1:1)=char(0)
line=char(0)
msgreceived=' '
max_iterations=10
niterations=0

View File

@ -222,19 +222,13 @@ program q65sim
fac=sqrt(1.0/avep)
cspread=fac*cspread !Normalize to constant avg power
cdat=cspread*cdat !Apply Rayleigh fading
endif
! psig=0.
! pnoise=0.
! do i=1,npts
! if(i.gt.12000 .and. i.lt.624000) then
! psig=psig + aimag(cdat(i))**2
! pnoise=pnoise + xnoise(i)*xnoise(i)
! endif
! do i=0,nfft-1
! p=real(cspread(i))**2 + aimag(cspread(i))**2
! write(14,3010) i,p,cspread(i)
!3010 format(i8,3f12.6)
! enddo
! pnoise=pnoise*bandwidth_ratio
! snr_2500=db(psig/pnoise) !Calibration confirmation!
! print*,'SNR_2500:',snr_2500
endif
dat=aimag(cdat) + xnoise !Add generated AWGN noise
fac=32767.0

View File

@ -1,75 +0,0 @@
subroutine foxgen2(nslots,cmsg,line,foxcall)
! Parse old-style Fox messages to extract the necessary pieces for a SuperFox
! transmission.
use packjt77
character*120 line
character*40 cmsg(5) !Old-style Fox messages are here
character*37 msg
character*26 sfmsg
character*13 mycall
character*11 foxcall
character*4 mygrid
character*6 hiscall_1,hiscall_2
character*4 rpt1,rpt2
character*13 w(19)
integer nw(19)
integer ntype !Message type: 0 Free Text
! 1 CQ MyCall MyGrid
! 2 Call_1 MyCall RR73
! 3 Call_1 MyCall rpt1
! 4 Call_1 RR73; Call_2 <MyCall> rpt2
if(nslots.lt.1 .or. nslots.gt.5) return
k=0
do i=1,nslots
hiscall_1=''
hiscall_2=''
mycall=''
mygrid=''
rpt1=''
rpt2=''
msg=cmsg(i)(1:37)
call split77(msg,nwords,nw,w)
ntype=0
if(msg(1:3).eq.'CQ ') then
ntype=1
mycall=w(2)(1:12)
mygrid=w(3)(1:4)
else if(index(msg,';').gt.0) then
ntype=4
hiscall_1=w(1)(1:6)
hiscall_2=w(3)(1:6)
rpt1='RR73'
rpt2=w(5)(1:4)
mycall=w(4)(2:nw(4)-1)
else if(index(msg,' RR73').gt.0) then
ntype=2
hiscall_1=w(1)(1:6)
mycall=w(2)(1:12)
rpt1='RR73'
else if(nwords.eq.3 .and. nw(3).eq.3 .and. &
(w(3)(1:1).eq.'-' .or. w(3)(1:1).eq.'+')) then
ntype=3
hiscall_1=w(1)(1:6)
mycall=w(2)(1:12)
rpt1=w(3)(1:4)
endif
k=k+1
if(ntype.le.3) call sfox_assemble(ntype,k,msg(1:26),mycall,mygrid,line)
if(ntype.eq.4) then
sfmsg=w(1)(1:nw(1))//' '//mycall(1:len(trim(mycall))+1)//'RR73'
call sfox_assemble(2,k,sfmsg,mycall,mygrid,line)
sfmsg=w(3)(1:nw(3))//' '//mycall(1:len(trim(mycall))+1)//w(5)(1:3)
k=k+1
call sfox_assemble(3,k,sfmsg,mycall,mygrid,line)
endif
enddo
call sfox_assemble(ntype,11,msg(1:26),mycall,mygrid,line) !k=11 to finish up
foxcall=mycall(1:11)
return
end subroutine foxgen2

View File

@ -1,12 +0,0 @@
! LDPC (174,91) code
parameter (KK=91) !Information bits (77 + CRC14)
parameter (ND=58) !Data symbols
parameter (NS=21) !Sync symbols (3 @ Costas 7x7)
parameter (NN=NS+ND) !Total channel symbols (79)
parameter (NSPS=1920) !Samples per symbol at 12000 S/s
parameter (NZ=NSPS*NN) !Samples in full 15 s waveform (151,680)
parameter (NMAX=15*12000) !Samples in iwave (180,000)
parameter (NFFT1=2*NSPS, NH1=NFFT1/2) !Length of FFTs for symbol spectra
parameter (NSTEP=NSPS/4) !Rough time-sync step size
parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps)
parameter (NDOWN=60) !Downsample factor

View File

@ -1,3 +0,0 @@
integer ntag
data ntag/z"1234567"/
!-----------------------------------------------------------------------

View File

@ -1,39 +0,0 @@
module julian
contains
integer*8 function itime8()
implicit integer (a-z)
! 1 2 3 4 5 6 7
integer it(8) !y m d nmin h m s
integer*8 secday
data secday/86400/
call date_and_time(values=it)
iyr=it(1)
imo=it(2)
iday=it(3)
days=JD(iyr,imo,iday) - 2440588 !Days since epoch Jan 1, 1970
ih=it(5)
im=it(6)-it(4) !it(4) corrects for time zone
is=it(7)
nsec=3600*ih + 60*im + is
itime8=days*secday + nsec
return
end function itime8
integer function JD(I,J,K)
! Return Julian Date for I=year, J=month, K=day
! Reference: Fliegel and Van Flandern, Comm. ACM 11, 10, 1968
JD = K - 32075 + 1461*(I + 4800 + (J - 14)/12)/4 &
+ 367*(J - 2 - (J - 14)/12*12)/12 - 3 &
*((I + 4900 + (J - 14)/12)/100)/4
return
end function JD
end module julian

View File

@ -1,103 +0,0 @@
!*******************************************************************************
!>
! A simple module for `popen`.
module popen_module
use,intrinsic :: iso_c_binding
implicit none
private
! interfaces to C functions
interface
function popen(command, mode) bind(C,name='popen')
!! initiate pipe streams to or from a process
import :: c_char, c_ptr
implicit none
character(kind=c_char),dimension(*) :: command
character(kind=c_char),dimension(*) :: mode
type(c_ptr) :: popen
end function popen
function fgets(s, siz, stream) bind(C,name='fgets')
!! get a string from a stream
import :: c_char, c_ptr, c_int
implicit none
type (c_ptr) :: fgets
character(kind=c_char),dimension(*) :: s
integer(kind=c_int),value :: siz
type(c_ptr),value :: stream
end function fgets
function pclose(stream) bind(C,name='pclose')
!! close a pipe stream to or from a process
import :: c_ptr, c_int
implicit none
integer(c_int) :: pclose
type(c_ptr),value :: stream
end function pclose
end interface
public :: c2f_string, get_command_as_string
contains
!*******************************************************************************
!>
! Convert a C string to a Fortran string.
function c2f_string(c) result(f)
character(len=*),intent(in) :: c !! C string
character(len=:),allocatable :: f !! Fortran string
integer :: i
i = index(c,c_null_char)
if (i<=0) then
f = c
else if (i==1) then
f = ''
else if (i>1) then
f = c(1:i-1)
end if
end function c2f_string
!*******************************************************************************
!>
! Return the result of the command as a string.
function get_command_as_string(command) result(str)
character(len=*),intent(in) :: command !! the command to run
character(len=:),allocatable :: str !! the result of that command
integer,parameter :: buffer_length = 1000 !! read stream in chunks of this size
type(c_ptr) :: h !! for `popen`
integer(c_int) :: istat !! `pclose` status
character(kind=c_char,len=buffer_length) :: line !! buffer to read from `fgets`
str = ''
h = c_null_ptr
h = popen(command//c_null_char,'r'//c_null_char)
if (c_associated(h)) then
do while (c_associated(fgets(line,buffer_length,h)))
str = str//c2f_string(line)
end do
istat = pclose(h)
end if
end function get_command_as_string
!*******************************************************************************
end module popen_module
!*******************************************************************************

View File

@ -1,67 +0,0 @@
// ------------------------------------------------------------------------------
// dbgprintf.c
// Functions for printing debug information
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// This source is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this source distribution.
// If not, see <http://www.gnu.org/licenses/>.
// ------------------------------------------------------------------------------
#include "dbgprintf.h"
// print functions for debug purposes
void dbgprintf_vector_uchar(const char* name, const unsigned char* v, int vsize)
{
int k;
printf("%s=", name);
for (k = 0; k < vsize; k++) {
if ((k & 0x0F) == 0)
printf("\n");
printf("%02X ", v[k]);
}
printf("\n");
}
void dbgprintf_vector_float(const char* name, const float* v, int vsize)
{
int k;
printf("%s=", name);
for (k = 0; k < vsize; k++) {
if ((k & 0x07) == 0)
printf("\n");
printf("%10.3f ", v[k]);
}
printf("\n");
}
void dbgprintf_rows_float(const char* name, const float* v, int vsize, int nrows)
{
int k;
int j;
printf("%s=\n", name);
for (j = 0; j < nrows; j++) {
printf("r%d:", j);
for (k = 0; k < vsize; k++) {
if ((k & 0x07) == 0)
printf("\n");
printf("%7.3f ", v[k]);
}
printf("\n");
v += vsize;
}
}

View File

@ -1,64 +0,0 @@
// ------------------------------------------------------------------------------
// dbgprintf.h
// Functions for printing debug information
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// This source is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this source distribution.
// If not, see <http://www.gnu.org/licenses/>.
// ------------------------------------------------------------------------------
#ifndef _dbgprintf_h_
#define _dbgprintf_h_
// Define DBGPRINTF_ANYWAY
// in order to print debug information also
// when _DEBUG is not defined
#define DBGPRINTF_ANYWAY
#ifdef _DEBUG
#define DBG_PRINTF
#else
#ifdef DBGPRINTF_ANYWAY
#define DBG_PRINTF
#endif
#endif
#include <stdio.h>
// print functions for debug purposes
#ifdef DBG_PRINTF
#ifdef __cplusplus
extern "C" {
#endif
void dbgprintf_vector_uchar(const char* name, const unsigned char* v, int vsize);
void dbgprintf_vector_float(const char* name, const float* v, int vsize);
void dbgprintf_rows_float(const char* name, const float* v, int vsize, int nrows);
#ifdef __cplusplus
}
#endif
#else
#define dbgprintf_vector_uchar(a,b)
#define dbgprintf_vector_float(a,b)
#define dbgprintf_rows_float(a, b, c, d)
#endif
#endif // _dbgprintf_h_

View File

@ -1,383 +0,0 @@
/*
File name: nhash2.c
*------------------------------------------------------------------------------
*
* This file is part of the WSPR application, Weak Signal Propogation Reporter
*
* File Name: nhash.c
* Description: Functions to produce 32-bit hashes for hash table lookup
*
* Copyright (C) 2008-2014 Joseph Taylor, K1JT
* License: GNU GPL v3+
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
* Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Files: lookup3.c
* Copyright: Copyright (C) 2006 Bob Jenkins <bob_jenkins@burtleburtle.net>
* License: public-domain
* You may use this code any way you wish, private, educational, or commercial.
* It's free.
*
*-------------------------------------------------------------------------------
*/
/*
These are functions for producing 32-bit hashes for hash table lookup.
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
are externally useful functions. Routines to test the hash are included
if SELF_TEST is defined. You can use this free for any purpose. It's in
the public domain. It has no warranty.
You probably want to use hashlittle(). hashlittle() and hashbig()
hash byte arrays. hashlittle() is is faster than hashbig() on
little-endian machines. Intel and AMD are little-endian machines.
On second thought, you probably want hashlittle2(), which is identical to
hashlittle() except it returns two 32-bit hashes for the price of one.
You could implement hashbig2() if you wanted but I haven't bothered here.
If you want to find a hash of, say, exactly 7 integers, do
a = i1; b = i2; c = i3;
mix(a,b,c);
a += i4; b += i5; c += i6;
mix(a,b,c);
a += i7;
final(a,b,c);
then use c as the hash value. If you have a variable length array of
4-byte integers to hash, use hashword(). If you have a byte array (like
a character string), use hashlittle(). If you have several byte arrays, or
a mix of things, see the comments above hashlittle().
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
then mix those integers. This is fast (you can do a lot more thorough
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
*/
#define SELF_TEST 1
#include <stdio.h> /* defines printf for tests */
#include <time.h> /* defines time_t for timings in the test */
#include "nhash2.h"
//#include <sys/param.h> /* attempt to define endianness */
//#ifdef linux
//# include <endian.h> /* attempt to define endianness */
//#endif
#define HASH_LITTLE_ENDIAN 1
#define hashsize(n) ((uint32_t)1<<(n))
#define hashmask(n) (hashsize(n)-1)
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
/*
-------------------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
This is reversible, so any information in (a,b,c) before mix() is
still in (a,b,c) after mix().
If four pairs of (a,b,c) inputs are run through mix(), or through
mix() in reverse, there are at least 32 bits of the output that
are sometimes the same for one pair and different for another pair.
This was tested for:
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
satisfy this are
4 6 8 16 19 4
9 15 3 18 27 15
14 9 3 7 17 3
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
for "differ" defined as + with a one-bit base and a two-bit delta. I
used http://burtleburtle.net/bob/hash/avalanche.html to choose
the operations, constants, and arrangements of the variables.
This does not achieve avalanche. There are input bits of (a,b,c)
that fail to affect some output bits of (a,b,c), especially of a. The
most thoroughly mixed value is c, but it doesn't really even achieve
avalanche in c.
This allows some parallelism. Read-after-writes are good at doubling
the number of bits affected, so the goal of mixing pulls in the opposite
direction as the goal of parallelism. I did what I could. Rotates
seem to cost as much as shifts on every machine I could lay my hands
on, and rotates are much kinder to the top and bottom bits, so I used
rotates.
-------------------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= c; a ^= rot(c, 4); c += b; \
b -= a; b ^= rot(a, 6); a += c; \
c -= b; c ^= rot(b, 8); b += a; \
a -= c; a ^= rot(c,16); c += b; \
b -= a; b ^= rot(a,19); a += c; \
c -= b; c ^= rot(b, 4); b += a; \
}
/*
-------------------------------------------------------------------------------
final -- final mixing of 3 32-bit values (a,b,c) into c
Pairs of (a,b,c) values differing in only a few bits will usually
produce values of c that look totally different. This was tested for
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
These constants passed:
14 11 25 16 4 14 24
12 14 25 16 4 14 24
and these came close:
4 8 15 26 3 22 24
10 8 15 26 3 22 24
11 8 15 26 3 22 24
-------------------------------------------------------------------------------
*/
#define final(a,b,c) \
{ \
c ^= b; c -= rot(b,14); \
a ^= c; a -= rot(c,11); \
b ^= a; b -= rot(a,25); \
c ^= b; c -= rot(b,16); \
a ^= c; a -= rot(c,4); \
b ^= a; b -= rot(a,14); \
c ^= b; c -= rot(b,24); \
}
/*
-------------------------------------------------------------------------------
hashlittle() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
length : the length of the key, counting by bytes
initval : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Two keys differing by one or two bits will have
totally different hash values.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (uint8_t **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial. It's free.
Use for hash table lookup, or anything where one collision in 2^^32 is
acceptable. Do NOT use for cryptographic purposes.
-------------------------------------------------------------------------------
*/
uint32_t nhash2( const void *key, uint64_t length, uint32_t initval)
//int nhash( const char *key, int length, int initval)
{
uint32_t a,b,c; /* internal state */
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
/* Set up the internal state */
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
u.ptr = key;
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
b += k[1];
c += k[2];
mix(a,b,c);
length -= 12;
k += 3;
}
// printf("AAA %x %d %x %d\n",c,c,c&32767,c&32767);
/*----------------------------- handle the last (probably partial) block */
/*
* "k[2]&0xffffff" actually reads beyond the end of the string, but
* then masks off the part it's not allowed to read. Because the
* string is aligned, the masked-off tail is in the same word as the
* rest of the string. Every machine with memory protection I've seen
* does it on word boundaries, so is OK with this. But VALGRIND will
* still catch it and complain. The masking trick does make the hash
* noticably faster for short strings (like English words).
*/
#ifndef VALGRIND
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
case 5 : b+=k[1]&0xff; a+=k[0]; break;
case 4 : a+=k[0]; break;
case 3 : a+=k[0]&0xffffff; break;
case 2 : a+=k[0]&0xffff; break;
case 1 : a+=k[0]&0xff; break;
case 0 : return c; /* zero length strings require no mixing */
}
#else /* make valgrind happy */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]; break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
case 1 : a+=k8[0]; break;
case 0 : return c;
}
#endif /* !valgrind */
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
const uint8_t *k8;
/*--------------- all but last block: aligned reads and different mixing */
while (length > 12)
{
a += k[0] + (((uint32_t)k[1])<<16);
b += k[2] + (((uint32_t)k[3])<<16);
c += k[4] + (((uint32_t)k[5])<<16);
mix(a,b,c);
length -= 12;
k += 6;
}
/*----------------------------- handle the last (probably partial) block */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=k[4];
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=k[2];
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=k[0];
break;
case 1 : a+=k8[0];
break;
case 0 : return c; /* zero length requires no mixing */
}
} else { /* need to read the key one byte at a time */
const uint8_t *k = (const uint8_t *)key;
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
a += ((uint32_t)k[1])<<8;
a += ((uint32_t)k[2])<<16;
a += ((uint32_t)k[3])<<24;
b += k[4];
b += ((uint32_t)k[5])<<8;
b += ((uint32_t)k[6])<<16;
b += ((uint32_t)k[7])<<24;
c += k[8];
c += ((uint32_t)k[9])<<8;
c += ((uint32_t)k[10])<<16;
c += ((uint32_t)k[11])<<24;
mix(a,b,c);
length -= 12;
k += 12;
}
/*-------------------------------- last block: affect all 32 bits of (c) */
switch(length) /* all the case statements fall through */
{
case 12: c+=((uint32_t)k[11])<<24;
/* fall through */
case 11: c+=((uint32_t)k[10])<<16;
/* fall through */
case 10: c+=((uint32_t)k[9])<<8;
/* fall through */
case 9 : c+=k[8];
/* fall through */
case 8 : b+=((uint32_t)k[7])<<24;
/* fall through */
case 7 : b+=((uint32_t)k[6])<<16;
/* fall through */
case 6 : b+=((uint32_t)k[5])<<8;
/* fall through */
case 5 : b+=k[4];
/* fall through */
case 4 : a+=((uint32_t)k[3])<<24;
/* fall through */
case 3 : a+=((uint32_t)k[2])<<16;
/* fall through */
case 2 : a+=((uint32_t)k[1])<<8;
/* fall through */
case 1 : a+=k[0];
break;
case 0 : return c;
}
}
final(a,b,c);
return c;
}

View File

@ -1,22 +0,0 @@
#ifndef NHASH_H_
#define NHASH_H_
#ifdef Win32
#include "win_stdint.h" /* defines uint32_t etc */
#else
#include <stddef.h>
#include <stdint.h> /* defines uint32_t etc */
#endif
#ifdef __cplusplus
extern "C" {
#endif
uint32_t nhash( const void * key, uint64_t length, uint32_t initval);
//int nhash(const char *key, int length, int initval);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,329 +0,0 @@
// ------------------------------------------------------------------------------
// np_qpc.h
// Q-Ary Polar Codes encoding/decoding functions
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// This source is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include "dbgprintf.h"
#include "qpc_fwht.h"
#include "np_qpc.h"
// static constant / functions
static const float knorm = 1.0f / QPC_Q;
static float* pdf_conv(float *dst, float* pdf1, float* pdf2)
{
// convolution between two pdf
float fwht_pdf1[QPC_Q];
float fwht_pdf2[QPC_Q];
int k;
qpc_fwht(fwht_pdf1, pdf1);
qpc_fwht(fwht_pdf2, pdf2);
for (k = 0; k < QPC_Q; k++)
fwht_pdf1[k] *= fwht_pdf2[k];
qpc_fwht(dst, fwht_pdf1);
for (k = 0; k < QPC_Q; k++)
dst[k] *= knorm;
return dst;
}
static void pdfarray_conv(float* dstarray, float* pdf1array, float* pdf2array, int numrows)
{
int k;
// convolutions between rows of pdfs
for (k = 0; k < numrows; k++) {
pdf_conv(dstarray, pdf1array, pdf2array);
dstarray += QPC_Q;
pdf1array += QPC_Q;
pdf2array += QPC_Q;
}
}
static float _pdfuniform[QPC_Q];
static const float* _pdf_uniform1();
static const float* _pdf_uniform0();
typedef const float*(*ptr_pdfuniform)(void);
static ptr_pdfuniform _ptr_pdf_uniform = _pdf_uniform0;
static const float* _pdf_uniform1()
{
return _pdfuniform;
};
static const float* _pdf_uniform0()
{
// compute uniform pdf once for all
int k;
for (k = 0; k < QPC_Q; k++)
_pdfuniform[k] = knorm;
// next call to _qpc_pdfuniform
// will be handled directly by _pqc_pdfuniform1
_ptr_pdf_uniform = _pdf_uniform1;
return _pdfuniform;
};
static const float* pdf_uniform()
{
return _ptr_pdf_uniform();
}
static float * pdf_mul(float *dst, float* pdf1, float* pdf2)
{
int k;
float v;
float norm = 0;
for (k = 0; k < QPC_Q; k++) {
v = pdf1[k] * pdf2[k];
dst[k] = v;
norm += v;
}
// if norm of the result is not positive
// return in dst a uniform distribution
if (norm <= 0)
memcpy(dst, pdf_uniform(), QPC_Q * sizeof(float));
else {
norm = 1.0f / norm;
for (k = 0; k < QPC_Q; k++)
dst[k] = dst[k] * norm;
}
return dst;
}
static void pdfarray_mul(float* dstarray, float* pdf1array, float* pdf2array, int numrows)
{
int k;
// products between rows of pdfs
for (k = 0; k < numrows; k++) {
pdf_mul(dstarray, pdf1array, pdf2array);
dstarray += QPC_Q;
pdf1array += QPC_Q;
pdf2array += QPC_Q;
}
}
static float* pdf_convhard(float* dst, const float* pdf, unsigned char hd)
{
// convolution between a pdf and a hard-decision feedback
int k;
for (k=0;k<QPC_Q;k++)
dst[k] = pdf[k^hd];
return dst;
}
static void pdfarray_convhard(float* dstarray, const float* pdfarray, const unsigned char *hdarray, int numrows)
{
int k;
// hard convolutions between rows
for (k = 0; k < numrows; k++) {
pdf_convhard(dstarray, pdfarray, hdarray[k]);
dstarray += QPC_Q;
pdfarray += QPC_Q;
}
}
static unsigned char pdf_max(const float* pdf)
{
int k;
unsigned char imax = 0;
float pdfmax = pdf[0];
for (k=1;k<QPC_Q;k++)
if (pdf[k] > pdfmax) {
pdfmax = pdf[k];
imax = k;
}
return imax;
}
// local stack functions ---------------------------------------
static float _qpc_stack[QPC_N * QPC_Q * 2];
static float* _qpc_stack_base = _qpc_stack;
static float* _qpc_stack_push(int numfloats)
{
float* addr = _qpc_stack_base;
_qpc_stack_base += numfloats;
return addr;
}
static void _qpc_stack_pop(int numfloats)
{
_qpc_stack_base -= numfloats;
}
// qpc encoder function (internal use) ----------------------------------------------------------
unsigned char* _qpc_encode(unsigned char* y, unsigned char* x)
{
// Non recursive polar encoder
// Same architecture of a fast fourier transform
// in which the fft butteflies are replaced by the polar transform
// butterflies
int k, j, m;
int groups;
int bfypergroup;
int stepbfy;
int stepgroup;
int basegroup;
int basebfy;
memcpy(y, x, QPC_N);
for (k = 0; k < QPC_LOG2N; k++) {
groups = 1 << (QPC_LOG2N - 1 - k);
stepbfy = bfypergroup = 1 << k;
stepgroup = stepbfy << 1;
basegroup = 0;
for (j = 0; j < groups; j++) {
basebfy = basegroup;
for (m = 0; m < bfypergroup; m++) {
// polar transform
y[basebfy + stepbfy] = y[basebfy + stepbfy] ^ y[basebfy];
basebfy = basebfy + 1;
}
basegroup = basegroup + stepgroup;
}
}
return y;
}
// qpc polar decoder (internal use )--------------------------------------------------
void _qpc_decode(unsigned char* xdec, unsigned char* ydec, const float* py, const unsigned char* f, const unsigned char* fsize, const int numrows)
{
if (numrows == 1) {
if (fsize[0] == 0) {
// dbgprintf_vector_float("py", py, QPC_Q);
// frozen symbol
xdec[0] = pdf_max(py);
ydec[0] = f[0];
}
else {
// fsize = 1 => information symbol
xdec[0] = pdf_max(py);
ydec[0] = xdec[0];
}
}
else {
int k;
int nextrows = numrows >> 1;
int size = nextrows << QPC_LOG2Q;
// upper block variables
unsigned char* xdech = xdec + nextrows;
unsigned char* ydech = ydec + nextrows;
const unsigned char* fh = f + nextrows;
const unsigned char* fsizeh = fsize + nextrows;
// Step 1.
// stack and init variables used in the recursion
float* pyl = _qpc_stack_push(size);
memcpy(pyl, py, size * sizeof(float));
float* pyh = _qpc_stack_push(size);
memcpy(pyh, py + size, size * sizeof(float));
// Step 2. Recursion on upper block
// Forward pdf convolutions for the upper block
// (place in the lower part of py the convolution of lower and higher blocks)
// float* pyh = py + size;
// pdfarray_conv(py, pyl, pyh, nextrows); // convolution overwriting the lower block of py which is not needed
pdfarray_conv(pyh, pyl, pyh, nextrows);
_qpc_decode(xdech, ydech, pyh, fh, fsizeh, nextrows);
// Step 3. compute pdfs in the lower block
pdfarray_convhard(pyh, py+size, ydech,nextrows); // dst ptr must be different form src ptr
pdfarray_mul(pyl, pyl, pyh, nextrows);
// we don't need pyh anymore
_qpc_stack_pop(size);
// Step 4. Recursion on the lower block
_qpc_decode(xdec, ydec, pyl, f, fsize, nextrows);
// we don't need pyl anymore
_qpc_stack_pop(size);
// Step 5. Update backward results
// xdec is already ok, we need just to update ydech
for (k = 0; k < nextrows; k++)
ydech[k] = ydech[k] ^ ydec[k];
}
}
// Public encoding/decoding functions ------------------------------------------------
void qpc_encode(unsigned char* y, const unsigned char* x)
{
// map information symbols
int kk, pos;
for (kk = 0; kk < QPC_K; kk++) {
pos = qpccode.xpos[kk];
qpccode.f[pos] = x[kk];
}
// do polar encoding
_qpc_encode(y, qpccode.f);
}
void qpc_decode(unsigned char* xdec, unsigned char* ydec, float* py)
{
int k;
unsigned char x[QPC_N];
// set the first py row with know frozen (punctured) symbol
if (qpccode.np < qpccode.n) {
// assume that we punctured only the first output symbol
memset(py, 0, QPC_Q * sizeof(float));
py[qpccode.f[0]] = 1.0f;
}
// decode
_qpc_decode(x, ydec, py, qpccode.f, qpccode.fsize, QPC_N);
// demap information symbols
for (k = 0; k < QPC_K; k++)
xdec[k] = x[qpccode.xpos[k]];
}

View File

@ -1,62 +0,0 @@
// ------------------------------------------------------------------------------
// np_qpc.h
// Q-Ary Polar Codes encoding/decoding functions
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// This source is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _np_qpc_h_
#define _np_qpc_h_
#define QPC_LOG2N 7 // log2(codeword length) (not punctured)
#define QPC_N (1<<QPC_LOG2N) // codeword length (not punctured)
#define QPC_LOG2Q 7 // bits per symbol
#define QPC_Q (1<<QPC_LOG2Q) // alphabet size
#define QPC_K 50 // number of information symbols
typedef struct {
int n; // codeword length (unpunctured)
int np; // codeword length (punctured)
int k; // number of information symbols
int q; // alphabet size
int xpos[QPC_N]; // info symbols mapping/demapping tables
unsigned char f[QPC_N]; // frozen symbols values
unsigned char fsize[QPC_N]; // frozen symbol flag (fsize==0 => frozen)
} qpccode_ds;
#ifdef __cplusplus
extern "C"
{
#endif
void qpc_encode(unsigned char* y, const unsigned char* x);
void qpc_decode(unsigned char* xdec, unsigned char* ydec, float* py);
unsigned char* _qpc_encode(unsigned char* y, unsigned char* x);
void _qpc_decode(unsigned char* xdec, unsigned char* ydec,
const float* py, const unsigned char* f, const unsigned char* fsize,
const int numrows);
extern qpccode_ds qpccode;
#ifdef __cplusplus
}
#endif
#endif // _np_qpc_h_

View File

@ -1,135 +0,0 @@
// ------------------------------------------------------------------------------
// np_rnd.c
// Functions to generate random numbers with uniform/gaussian probability distributions
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// This source is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include "np_rnd.h"
#if _WIN32 // note the underscore: without it, it's not msdn official!
// Windows (x64 and x86)
#include <windows.h> // required only for GetTickCount(...)
#define K_RAND_MAX UINT_MAX
#elif _SVID_SOURCE || _XOPEN_SOURCE || __unix__ || (defined (__APPLE__) && defined(__MACH__)) /* POSIX or Unix or Apple */
#include <stdlib.h>
#define rand_s(x) (*x)=(unsigned int)lrand48() // returns unsigned integers in the range 0..0x7FFFFFFF
#define K_RAND_MAX 0x7FFFFFFF // that's the max number
// generated by lrand48
#else
#error "No good quality PRNG found"
#endif
void np_normrnd_real(float *dst, int nitems, float mean, float stdev)
{
// for odd or even nitems
unsigned int r;
float phi=0, u=0;
int set = 0;
float scalephi = (M_2PI / (1.0f + K_RAND_MAX));
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
while (nitems--)
if (set==1) {
// generate a second normally distributed number
*dst++ = sinf(phi)*u*stdev+mean;
set = 0;
}
else {
// generate a uniform distributed phase phi in the range [0,2*PI)
rand_s((unsigned int*)&r); phi = scalephi * r;
// generate a uniform distributed random number u in the range (0,1]
rand_s((unsigned int*)&r); u = scaleu * (1.0f + r);
// generate normally distributed number
u = (float)sqrt(-2.0f * log(u));
*dst++ = cosf(phi) * u * stdev + mean;
set=1;
}
}
void np_normrnd_cpx(float* dst, int nitems, float mean, float stdev)
{
// as qpc_normrnd_real, but generates always nitems complex numbers (2*nitems reals)
unsigned int r;
float phi = 0, u = 0;
// JHT int set = 0;
float scalephi = (M_2PI / (1.0f + K_RAND_MAX));
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
while (nitems--) {
// generate a uniform distributed phase phi in the range [0,2*PI)
rand_s((unsigned int*)&r); phi = scalephi * r;
// generate a uniform distributed random number u in the range (0,1]
rand_s((unsigned int*)&r); u = scaleu * (1.0f + r);
// generate normally distributed real and imaginary parts
u = (float)sqrt(-2.0f * log(u));
*dst++ = cosf(phi) * u * stdev + mean;
*dst++ = sinf(phi) * u * stdev + mean;
}
}
void np_unidrnd(unsigned int* dst, int nitems, unsigned int nsetsize)
{
// generate uniform unsigned int random numbers in the range [0..nsetsize)
unsigned int r;
float u;
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
while (nitems--) {
rand_s((unsigned int*)&r); u = scaleu * nsetsize * r;
*dst++ = (unsigned int)floorf(u);
}
}
void np_unidrnd_uc(unsigned char* dst, int nitems, unsigned char nsetsize)
{
// generate uniform unsigned char random numbers in the range [0..nsetsize)
unsigned int r;
float u;
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
while (nitems--) {
rand_s((unsigned int*)&r); u = scaleu * nsetsize * r;
*dst++ = (unsigned char)floorf(u);
}
}
void np_unifrnd(float* dst, int nitems, float fmax)
{
// generate uniform float random numbers in the range [0..fmax)
unsigned int r;
float u;
float scaleu = (1.0f / (1.0f + K_RAND_MAX));
while (nitems--) {
rand_s((unsigned int*)&r); u = scaleu * fmax * r;
*dst++ = u;
}
}

View File

@ -1,59 +0,0 @@
// ------------------------------------------------------------------------------
// np_rnd.h
// Functions to generate random numbers with uniform/gaussian probability distributions
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// This source is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _np_rnd_h_
#define _np_rnd_h_
#define _CRT_RAND_S
#include <stdlib.h>
#define _USE_MATH_DEFINES
#include <math.h>
#define M_2PI (2.0f*(float)M_PI)
#ifdef __cplusplus
extern "C" {
#endif
// generate a random array of real numbers with a gaussian distribution of given mean and stdev
void np_normrnd_real(float *dst, int nitems, float mean, float stdev);
// generate a random array of nitems complex numbers with a gaussian distribution of given mean and stdev
void np_normrnd_cpx(float* dst, int nitems, float mean, float stdev);
// generate a random array of nitems unsigned int numbers with uniform distribution
// in the range [0 .. nsetsize)
void np_unidrnd(unsigned int* dst, int nitems, unsigned int nsetsize);
// generate a random array of nitems unsigned chars numbers with uniform distribution
// in the range [0 .. nsetsize)
void np_unidrnd_uc(unsigned char* dst, int nitems, unsigned char nsetsize);
// generate a random array of nitems float numbers with uniform distribution
// in the range [0 .. fmax)
void np_unifrnd(float* dst, int nitems, float fmax);
#ifdef __cplusplus
}
#endif
#endif // _np_rnd_h_

View File

@ -1,233 +0,0 @@
// ------------------------------------------------------------------------------
// qpc_fwht.c
// Fast Walsh-Hadamard Transforms for q-ary polar codes
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// This source is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#include "qpc_fwht.h"
static void _qpc_sumdiff8_16(float* y, float* t)
{
y[0] = t[0] + t[16];
y[16] = t[0] - t[16];
y[1] = t[1] + t[17];
y[17] = t[1] - t[17];
y[2] = t[2] + t[18];
y[18] = t[2] - t[18];
y[3] = t[3] + t[19];
y[19] = t[3] - t[19];
y[4] = t[4] + t[20];
y[20] = t[4] - t[20];
y[5] = t[5] + t[21];
y[21] = t[5] - t[21];
y[6] = t[6] + t[22];
y[22] = t[6] - t[22];
y[7] = t[7] + t[23];
y[23] = t[7] - t[23];
}
static void _qpc_sumdiff8_32(float* y, float* t)
{
y[0] = t[0] + t[32];
y[32] = t[0] - t[32];
y[1] = t[1] + t[33];
y[33] = t[1] - t[33];
y[2] = t[2] + t[34];
y[34] = t[2] - t[34];
y[3] = t[3] + t[35];
y[35] = t[3] - t[35];
y[4] = t[4] + t[36];
y[36] = t[4] - t[36];
y[5] = t[5] + t[37];
y[37] = t[5] - t[37];
y[6] = t[6] + t[38];
y[38] = t[6] - t[38];
y[7] = t[7] + t[39];
y[39] = t[7] - t[39];
}
static void _qpc_sumdiff8_64(float* y, float* t)
{
y[0] = t[0] + t[64];
y[64] = t[0] - t[64];
y[1] = t[1] + t[65];
y[65] = t[1] - t[65];
y[2] = t[2] + t[66];
y[66] = t[2] - t[66];
y[3] = t[3] + t[67];
y[67] = t[3] - t[67];
y[4] = t[4] + t[68];
y[68] = t[4] - t[68];
y[5] = t[5] + t[69];
y[69] = t[5] - t[69];
y[6] = t[6] + t[70];
y[70] = t[6] - t[70];
y[7] = t[7] + t[71];
y[71] = t[7] - t[71];
}
float* qpc_fwht8(float* y, float* x)
{
float t[8];
// first stage
y[0] = x[0] + x[1];
y[1] = x[0] - x[1];
y[2] = x[2] + x[3];
y[3] = x[2] - x[3];
y[4] = x[4] + x[5];
y[5] = x[4] - x[5];
y[6] = x[6] + x[7];
y[7] = x[6] - x[7];
// second stage
t[0] = y[0] + y[2];
t[2] = y[0] - y[2];
t[1] = y[1] + y[3];
t[3] = y[1] - y[3];
t[4] = y[4] + y[6];
t[6] = y[4] - y[6];
t[5] = y[5] + y[7];
t[7] = y[5] - y[7];
// third stage
y[0] = t[0] + t[4];
y[4] = t[0] - t[4];
y[1] = t[1] + t[5];
y[5] = t[1] - t[5];
y[2] = t[2] + t[6];
y[6] = t[2] - t[6];
y[3] = t[3] + t[7];
y[7] = t[3] - t[7];
return y;
}
float* qpc_fwht16(float* y, float* x)
{
float t[16];
qpc_fwht8(t, x);
qpc_fwht8(t + 8, x + 8);
y[0] = t[0] + t[8];
y[8] = t[0] - t[8];
y[1] = t[1] + t[9];
y[9] = t[1] - t[9];
y[2] = t[2] + t[10];
y[10] = t[2] - t[10];
y[3] = t[3] + t[11];
y[11] = t[3] - t[11];
y[4] = t[4] + t[12];
y[12] = t[4] - t[12];
y[5] = t[5] + t[13];
y[13] = t[5] - t[13];
y[6] = t[6] + t[14];
y[14] = t[6] - t[14];
y[7] = t[7] + t[15];
y[15] = t[7] - t[15];
return y;
}
float* qpc_fwht32(float* y, float* x)
{
float t[32];
qpc_fwht16(t, x);
qpc_fwht16(t + 16, x + 16);
_qpc_sumdiff8_16(y, t);
_qpc_sumdiff8_16(y + 8, t + 8);
return y;
}
float* qpc_fwht64(float* y, float* x)
{
float t[64];
qpc_fwht32(t, x);
qpc_fwht32(t + 32, x + 32);
_qpc_sumdiff8_32(y, t);
_qpc_sumdiff8_32(y + 8, t + 8);
_qpc_sumdiff8_32(y + 16, t + 16);
_qpc_sumdiff8_32(y + 24, t + 24);
return y;
}
float* qpc_fwht128(float* y, float* x)
{
float t[128];
qpc_fwht64(t, x);
qpc_fwht64(t + 64, x + 64);
_qpc_sumdiff8_64(y, t);
_qpc_sumdiff8_64(y + 8, t + 8);
_qpc_sumdiff8_64(y + 16, t + 16);
_qpc_sumdiff8_64(y + 24, t + 24);
_qpc_sumdiff8_64(y + 32, t + 32);
_qpc_sumdiff8_64(y + 40, t + 40);
_qpc_sumdiff8_64(y + 48, t + 48);
_qpc_sumdiff8_64(y + 56, t + 56);
return y;
}
// functions over pdfs used by the decoder -----------------------------------------------------------

View File

@ -1,57 +0,0 @@
// ------------------------------------------------------------------------------
// qpc_fwht.h
// Fast Walsh-Hadamard Transforms for q-ary polar codes
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// This source is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this source distribution.
// If not, see <http://www.gnu.org/licenses/>.
#ifndef _qpc_fwht_h_
#define _qpc_fwht_h_
#include "np_qpc.h"
#if QPC_LOG2Q==7
#define qpc_fwht(a,b) qpc_fwht128(a,b)
#endif
#if QPC_LOG2Q==6
#define qpc_fwht(a,b) qpc_fwht64(a,b)
#endif
#if QPC_LOG2Q==5
#define qpc_fwht(a,b) qpc_fwht32(a,b)
#endif
#if QPC_LOG2Q==4
#define qpc_fwht(a,b) qpc_fwht16(a,b)
#endif
// Note that it makes no sense to use fast convolutions
// for transforms that are less than 16 symbols in size.
// For such cases direct convolutions are faster.
#if QPC_LOG2Q==3
#define qpc_fwht(a,b) qpc_fwht8(a,b)
#endif
#ifdef __cplusplus
extern "C" {
#endif
float* qpc_fwht8(float* y, float* x);
float* qpc_fwht16(float* y, float* x);
float* qpc_fwht32(float* y, float* x);
float* qpc_fwht64(float* y, float* x);
float* qpc_fwht128(float* y, float* x);
#ifdef __cplusplus
}
#endif
#endif // _qpc_fwht_h_

View File

@ -1,198 +0,0 @@
// ------------------------------------------------------------------------------
// qpc_main.cpp
//
// Test the WER performance of the QPC (127,50) Q=128 code
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include "dbgprintf.h"
#include "qpc_fwht.h"
#include "np_qpc.h"
// for random numbers generation and NCFSK Rayleigh channel simulation
#include "np_rnd.h"
void qpc_channel(float* yout, unsigned char* y, float EsNo)
{
// compute channel outputs amplitudes
int k;
// generate noise samples -----------------------------------------
float sigman = 1.0f / sqrtf(2.0f);
np_normrnd_cpx(yout, QPC_N * QPC_Q, 0, sigman);
// dbgprintf_rows_float("yout", yout, QPC_Q*2, QPC_N);
// generate rayleigh distributed signal amplitudes -----------------
float symamps[QPC_N * 2];
np_normrnd_cpx(symamps, QPC_N, 0, sigman);
// dbgprintf_vector_float("symamps", symamps, QPC_N*2);
// normalize signal amps to unity ----------------------------------
float pwr = 0.0f;
float* psymamps = symamps;
// compute sig power
for (k = 0; k < QPC_N; k++) {
pwr += psymamps[0] * psymamps[0] + psymamps[1] * psymamps[1];
psymamps += 2;
}
pwr = pwr / QPC_N;
// normalize to avg EsNo
float norm = sqrtf(EsNo/pwr);
psymamps = symamps;
for (k = 0; k < QPC_N; k++) {
psymamps[0] *= norm;
psymamps[1] *= norm;
psymamps += 2;
}
// dbgprintf_vector_float("symamps norm", symamps, QPC_N * 2);
// add signal amplitudes to noise -----------------------------------
float *pyout = yout;
psymamps= symamps;
for (k = 0; k < QPC_N; k++) {
pyout[y[k]<<1] += psymamps[0];
pyout[(y[k]<<1)+1] += psymamps[1];
pyout += (QPC_Q*2);
psymamps += 2;
}
// dbgprintf_rows_float("s+n out", yout, QPC_Q * 2, QPC_N);
return;
}
void qpc_likelihoods(float* py, float* yout, float EsNo, float No)
{
// compute symbols likelihoods
// (rayleigh channel)
int k, j;
float norm = EsNo / (EsNo + 1) / No;
// compute likelihoods from energies ----------------------------
float* pybase;
float* ppyout = yout;
float normpwr;
float normpwrmax;
float pynorm;
for (k = 0; k < QPC_N; k++) {
// compute loglikelihoods and largest one from energies
pybase = py + k * QPC_Q;
normpwrmax = 0.0f;
for (j = 0; j < QPC_Q; j++) {
normpwr = norm * (ppyout[0] * ppyout[0] + ppyout[1] * ppyout[1]);
pybase[j] = normpwr;
if (normpwr > normpwrmax)
normpwrmax = normpwr;
ppyout += 2;
}
// subtract largest exponent
pynorm = 0.0f;
for (j = 0; j < QPC_Q; j++) {
pybase[j] = expf(pybase[j] - normpwrmax);
pynorm += pybase[j];
}
// normalize to probabilities
pynorm = 1.0f / pynorm;
for (j = 0; j < QPC_Q; j++)
pybase[j] = pybase[j] * pynorm;
}
return;
}
int main()
{
int k;
int NT = 20000; // number of transmissions to simultate
float EbNodB = 3.7f; // Eb/No to simulate
int kc = qpccode.k;
int np = qpccode.np;
float Rc = 1.0f * kc / np;
float Tm = 10.0f; // message duration
float Rb = 1.0f / Tm * (QPC_K - 2) * QPC_LOG2Q; // Bit rate assuming two symbols for CRC
float EsNodB = EbNodB + 10.0f * log10f(Rc * QPC_LOG2Q);
static unsigned char xin[QPC_K]; // input information symbols
static unsigned char xdec[QPC_K]; // decoded information symbols
static unsigned char y[QPC_N]; // encoded codeword
static unsigned char ydec[QPC_N]; // decoded codeword
static float yout[QPC_N * QPC_Q * 2]; // channel complex amplitutes output
static float py[QPC_N * QPC_Q]; // channel output probabilities
float EsNo = powf(10.0f, EsNodB / 10.0f);
float No = 1.0f;
//JHT static float we;
static float wer;
int kk;
printf("QPC Word Error Rate Test\n");
printf("Polar Code (%d,%d) Q=%d for the Rayleigh channel\n", qpccode.np, qpccode.k, qpccode.q);
printf("Eb/No = %.1f dB\n", EbNodB);
printf("Es/No = %.1f dB\n", EsNodB);
printf("Tmsg = %.1f s\n", Tm);
printf("Bit Rate = %.1f bit/s\n", Rb);
printf("SNR(2500) = %.1f dB\n\n", EbNodB + 10.0f * log10f(Rb/ 2500));
for (k = 0; k < NT; k++) {
np_unidrnd_uc(xin, QPC_K, QPC_Q); // generate random information symbols
qpc_encode(y, xin); // encode
// compute channel outputs and probabilities
// Note that if the code is punctured (i.e. N=127)
// the first codeword symbol must not be transmitted over the channel
// Here, in order to avoid useless copies,
// the vector of likelihoods py continues to be a QPC_N*QPC_Q vector of floats.
// The first received symbol likelihoods should start always at offset QPC_Q.
// The first QPC_Q positions of py will be ignored (and set) by the decoder.
qpc_channel(yout, y, EsNo);
// The decoder can't estimate the EsNo easily
// so we assume that in any case it is 5 dB
float EsNoDec = 3.16;
qpc_likelihoods(py, yout, EsNoDec, No);
qpc_decode(xdec, ydec, py); // decode
// count words in errors
for (kk = 0; kk < QPC_K; kk++)
if (xin[kk] ^ xdec[kk]) {
wer += 1;
break;
}
// show the decoder performance every 200 codewords transmissions
if ((k % 200) == 0 && k>0) {
printf("k=%6d/%6d wer = %8.2E\n", k, NT, wer / k);
fflush(stdout);
}
}
// show the final result
printf("k=%6d/%6d wer = %8.2E\n", k, NT, wer / k);
printf("\nAll done.\n");
return 0;
}

View File

@ -1,38 +0,0 @@
module qpc_mod
interface
integer(c_int32_t) function nhash2 (xin, length, initval) bind(C, &
name="nhash2")
use iso_c_binding, only: c_signed_char, c_int64_t, c_int32_t
integer(c_int64_t), intent(in), value :: length
integer(c_signed_char), intent(in) :: xin(length)
integer(c_int32_t), intent(in), value :: initval
end function nhash2
end interface
interface
subroutine qpc_encode(y, xin) bind(C,name="qpc_encode")
use iso_c_binding, only: c_ptr, c_signed_char
integer(c_signed_char), intent(out) :: y(127)
integer(c_signed_char), intent(in) :: xin(50)
end subroutine qpc_encode
end interface
interface
subroutine qpc_channel(yout, y, EsNo) bind(C,name="qpc_channel")
use iso_c_binding, only: c_float_complex, c_float, c_signed_char
complex(c_float_complex), intent(out) :: yout(128,128)
integer(c_signed_char), intent(out) :: y(127)
real(c_float), intent(in), value :: EsNo
end subroutine qpc_channel
end interface
interface
subroutine qpc_decode(xdec, ydec, py) bind(C,name="qpc_decode")
use iso_c_binding, only: c_float, c_signed_char
real(c_float), intent(in) :: py(128,128)
integer(c_signed_char), intent(out) :: ydec(127)
integer(c_signed_char), intent(out) :: xdec(50)
end subroutine qpc_decode
end interface
end module qpc_mod

View File

@ -1,60 +0,0 @@
// ------------------------------------------------------------------------------
// qpc_n127k50q128.c
//
// Defines the parameters of the q-ary polar code (127,50) Q=128
// for WSJT-X
// ------------------------------------------------------------------------------
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
//
// WARNING:
// This source is NOT free software and it is licensed only for use with WSJT-X.
// No derived work is authorized to use this code without the written
// permission of his author (Nico Palermo / IV3NWV) who owns all the rights
// of this IP (intellectual property).
//
// This file is distributed ONLY for the purpose of documenting and making of
// public domain the encoding scheme used in WSJT-X so that the transmitted
// messages can be decoded by anybody.
// Anyway this does not imply that one could use the following tables in a
// derived work without an explicit and written authorization from his author.
// Any unauthorized use, as for any intellectual property, is simply
// illegal.
// -------------------------------------------------------------------------------
#include "np_qpc.h"
qpccode_ds qpccode = {
128, //n
127, //np
50, //k
128, //q
{
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 16, 32, 17, 18, 64, 20,
33, 34, 24, 7, 11, 36, 13, 19, 14, 65, 40, 21, 66, 22, 35, 68,
25, 48, 37, 26, 72, 15, 38, 28, 41, 67, 23, 80, 42, 69, 49, 96,
44, 27, 70, 50, 73, 39, 29, 52, 74, 30, 56, 81, 76, 43, 82, 84,
97, 45, 71, 88, 98, 46, 100, 51, 104, 53, 75, 112, 54, 57, 99, 119,
92, 77, 58, 117, 59, 83, 106, 31, 85, 108, 115, 116, 122, 125, 124, 91,
61, 90, 89, 111, 78, 93, 94, 126, 86, 107, 110, 118, 121, 62, 120, 87,
105, 55, 114, 60, 127, 63, 103, 101, 123, 95, 102, 47, 109, 79, 113, 0
},
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
},
{
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0,
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
}
};

View File

@ -1,115 +0,0 @@
// ------------------------------------------------------------------------------
// qpc_test.cpp
//
// Test the WER performance of the QPC (127,50) Q=128 code
//
// (c) 2024 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy
// ------------------------------------------------------------------------------
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <time.h>
#include "dbgprintf.h"
#include "qpc_fwht.h"
#include "np_qpc.h"
#include "nhash2.h"
// for random numbers generation and NCFSK Rayleigh channel simulation
#include "np_rnd.h"
void qpc_channel(float* yout, unsigned char* y, float EsNo)
{
// compute channel outputs amplitudes
int k;
// generate noise samples -----------------------------------------
float sigman = 1.0f / sqrtf(2.0f);
np_normrnd_cpx(yout, QPC_N * QPC_Q, 0, sigman);
// dbgprintf_rows_float("yout", yout, QPC_Q*2, QPC_N);
// generate rayleigh distributed signal amplitudes -----------------
float symamps[QPC_N * 2];
np_normrnd_cpx(symamps, QPC_N, 0, sigman);
// dbgprintf_vector_float("symamps", symamps, QPC_N*2);
// normalize signal amps to unity ----------------------------------
float pwr = 0.0f;
float* psymamps = symamps;
// compute sig power
for (k = 0; k < QPC_N; k++) {
pwr += psymamps[0] * psymamps[0] + psymamps[1] * psymamps[1];
psymamps += 2;
}
pwr = pwr / QPC_N;
// normalize to avg EsNo
float norm = sqrtf(EsNo/pwr);
psymamps = symamps;
for (k = 0; k < QPC_N; k++) {
psymamps[0] *= norm;
psymamps[1] *= norm;
psymamps += 2;
}
// dbgprintf_vector_float("symamps norm", symamps, QPC_N * 2);
// add signal amplitudes to noise -----------------------------------
float *pyout = yout;
psymamps= symamps;
for (k = 0; k < QPC_N; k++) {
pyout[y[k]<<1] += psymamps[0];
pyout[(y[k]<<1)+1] += psymamps[1];
pyout += (QPC_Q*2);
psymamps += 2;
}
// dbgprintf_rows_float("s+n out", yout, QPC_Q * 2, QPC_N);
return;
}
void qpc_likelihoods(float* py, float* yout, float EsNo, float No)
{
// compute symbols likelihoods
// (rayleigh channel)
int k, j;
float norm = EsNo / (EsNo + 1) / No;
// compute likelihoods from energies ----------------------------
float* pybase;
float* ppyout = yout;
float normpwr;
float normpwrmax;
float pynorm;
for (k = 0; k < QPC_N; k++) {
// compute loglikelihoods and largest one from energies
pybase = py + k * QPC_Q;
normpwrmax = 0.0f;
for (j = 0; j < QPC_Q; j++) {
normpwr = norm * (ppyout[0] * ppyout[0] + ppyout[1] * ppyout[1]);
pybase[j] = normpwr;
if (normpwr > normpwrmax)
normpwrmax = normpwr;
ppyout += 2;
}
// subtract largest exponent
pynorm = 0.0f;
for (j = 0; j < QPC_Q; j++) {
pybase[j] = expf(pybase[j] - normpwrmax);
pynorm += pybase[j];
}
// normalize to probabilities
pynorm = 1.0f / pynorm;
for (j = 0; j < QPC_Q; j++)
pybase[j] = pybase[j] * pynorm;
}
return;
}

View File

@ -1,150 +0,0 @@
subroutine qpc_decode2(c0,fsync,ftol,xdec,ndepth,dth,damp,crc_ok, &
snrsync,fbest,tbest,snr)
use qpc_mod
parameter(NMAX=15*12000,NFT=365,NZ=100)
complex c0(NMAX) !Signal as received
complex c(NMAX) !Signal as received
real py(0:127,0:127) !Probabilities for received synbol values
real py0(0:127,0:127) !Probabilities for strong signal
real pyd(0:127,0:127) !Dithered values for py
real s2(0:127,0:151) !Symbol spectra, including sync
real s3(0:127,0:127) !Synchronized symbol spectra
real No
integer crc_chk,crc_sent
integer*8 n47
integer idf(NZ),idt(NZ)
integer nseed(33)
integer*1 xdec(0:49) !Decoded message
integer*1 ydec(0:127) !Decoded symbols
logical crc_ok
integer maxdither(8)
integer isync(24) !Symbol numbers for sync tones
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80,83, &
84,86,89/
data n47/47/,maxdither/20,50,100,200,500,1000,2000,5000/
data nseed/ &
321278106, -658879006, 1239150429, -941466001, -698554454, &
1136210962, 1633585627, 1261915021, -1134191465, -487888229, &
2131958895, -1429290834, -1802468092, 1801346659, 1966248904, &
402671397, -1961400750, -1567227835, 1895670987, -286583128, &
-595933665, -1699285543, 1518291336, 1338407128, 838354404, &
-2081343776, -1449416716, 1236537391, -133197638, 337355509, &
-460640480, 1592689606, 0/
data idf/0, 0, -1, 0, -1, 1, 0, -1, 1, -2, 0, -1, 1, -2, 2, &
0, -1, 1, -2, 2, -3, 0, -1, 1, -2, 2, -3, 3, 0, -1, &
1, -2, 2, -3, 3, -4, 0, -1, 1, -2, 2, -3, 3, -4, 4, &
0, -1, 1, -2, 2, -3, 3, -4, 4, -5, -1, 1, -2, 2, -3, &
3, -4, 4, -5, 1, -2, 2, -3, 3, -4, 4, -5, -2, 2, -3, &
3, -4, 4, -5, 2, -3, 3, -4, 4, -5, -3, 3, -4, 4, -5, &
3, -4, 4, -5, -4, 4, -5, 4, -5, -5/
data idt/0 , -1, 0, 1, -1, 0, -2, 1, -1, 0, 2, -2, 1, -1, 0, &
-3, 2, -2, 1, -1, 0, 3, -3, 2, -2, 1, -1, 0, -4, 3, &
-3, 2, -2, 1, -1, 0, 4, -4, 3, -3, 2, -2, 1, -1, 0, &
-5, 4, -4, 3, -3, 2, -2, 1, -1, 0, -5, 4, -4, 3, -3, &
2, -2, 1, -1, -5, 4, -4, 3, -3, 2, -2, 1, -5, 4, -4, &
3, -3, 2, -2, -5, 4, -4, 3, -3, 2, -5, 4, -4, 3, -3, &
-5, 4, -4, 3, -5, 4, -4, -5, 4, -5/
fsample=12000.0
baud=12000.0/1024.0
nstype=1
n47=47
mask21=2**21 - 1
crc_ok=.false.
call qpc_sync(c0,fsample,isync,fsync,ftol,f2,t2,snrsync)
f00=1500.0 + f2
t00=t2
fbest=f00
tbest=t00
maxd=1
if(ndepth.gt.0) maxd=maxdither(ndepth)
maxft=NZ
if(snrsync.lt.4.0 .or. ndepth.le.0) maxft=1
do idith=1,maxft
if(idith.ge.2) maxd=1
deltaf=idf(idith)*0.5
deltat=idt(idith)*8.0/1024.0
f=f00+deltaf
t=t00+deltat
fshift=1500.0 - (f+baud) !Shift frequencies down by f + 1 bin
call twkfreq2(c0,c,NMAX,fsample,fshift)
a=1.0
b=0.0
do kk=1,4
if(kk.eq.2) b=0.4
if(kk.eq.3) b=0.5
if(kk.eq.4) b=0.6
call sfox_demod(c,1500.0,t,isync,s2,s3) !Compute s2 and s3
if(b.gt.0.0) then
do j=0,127
call smo121a(s3(:,j),128,a,b)
enddo
endif
call pctile(s3,128*128,50,base3)
s3=s3/base3
EsNoDec=3.16
No=1.
py0=s3
call qpc_likelihoods2(py,s3,EsNoDec,No) !For weak signals
call random_seed(put=nseed)
do kkk=1,maxd
if(kkk.eq.1) then
pyd=py0
else
pyd=0.
if(kkk.gt.2) then
call random_number(pyd)
pyd=2.0*(pyd-0.5)
endif
where(py.gt.dth) pyd=0. !Don't perturb large likelihoods
pyd=py*(1.0 + damp*pyd) !Compute dithered likelihood
endif
do j=0,127
ss=sum(pyd(:,j))
if(ss.gt.0.0) then
pyd(:,j)=pyd(:,j)/ss
else
pyd(:,j)=0.0
endif
enddo
call qpc_decode(xdec,ydec,pyd)
xdec=xdec(49:0:-1)
crc_chk=iand(nhash2(xdec,n47,571),mask21) !Compute crc_chk
crc_sent=128*128*xdec(47) + 128*xdec(48) + xdec(49)
crc_ok=crc_chk.eq.crc_sent
if(crc_ok) then
call qpc_snr(s3,ydec,snr)
if(snr.lt.-16.5) crc_ok=.false.
! write(61,3061) idith,kk,kkk,idf(idith),idt(idith),a,b
!3061 format(5i5,2f8.3)
return
endif
enddo !kk: dither of smoothing weights
enddo !kkk: dither of probabilities
enddo !idith: dither of frequency and time
return
end subroutine qpc_decode2
subroutine smo121a(x,nz,a,b)
real x(nz)
fac=1.0/(a+2*b)
x0=x(1)
do i=2,nz-1
x1=x(i)
x(i)=fac*(a*x(i) + b*(x0+x(i+1)))
x0=x1
enddo
return
end subroutine smo121a

View File

@ -1,28 +0,0 @@
subroutine qpc_likelihoods2(py,s3,EsNo,No)
integer QQ,QN
parameter(QQ=128,QN=128)
real py(0:QQ-1,0:QN-1)
real s3(0:QQ-1,0:QN-1)
real No,norm,normpwr,normpwrmax
norm=(EsNo/(EsNo+1.0))/No
! Compute likelihoods for symbol values, from the symbol power spectra
do k=0,QN-1
normpwrmax=0.
do j=0,QQ-1
normpwr=norm*s3(j,k)
py(j,k)=normpwr
normpwrmax=max(normpwr,normpwrmax)
enddo
pynorm=0.
do j=0,QQ-1
py(j,k)=exp(py(j,k)-normpwrmax)
pynorm=pynorm + py(j,k)
enddo
py(0:QQ-1,k)=py(0:QQ-1,k)/pynorm !Normalize to probabilities
enddo
return
end subroutine qpc_likelihoods2

View File

@ -1,17 +0,0 @@
subroutine qpc_snr(s3,y,snr)
use qpc_mod
! real s2(0:NQ-1,0:151) !Symbol spectra, including sync
real s3(0:127,0:127) !Synchronized symbol spectra
integer*1 y(0:127) !Encoded symbols
! integer isync(24)
p=0.
do j=1,127
i=y(j)
p=p + s3(i,j)
enddo
snr=db(p/127.0) - db(127.0) - 4.0
return
end subroutine qpc_snr

View File

@ -1,101 +0,0 @@
subroutine qpc_sync(crcvd0,fsample,isync,fsync,ftol,f2,t2,snrsync)
parameter(N9SEC=9*12000,NMAX=15*12000,NDOWN=16,NZ=N9SEC/NDOWN)
complex crcvd0(NMAX) !Signal as received
complex c0(0:N9SEC-1) !For long FFT
complex c1(0:NZ-1)
complex c1sum(0:NZ-1)
complex z
real s(N9SEC/4)
real p(-1125:1125)
integer ipk(1)
integer isync(24)
baud=12000.0/1024.0
df2=fsample/N9SEC
fac=1.0/N9SEC
c0=fac*crcvd0(1:N9SEC)
call four2a(c0,N9SEC,1,-1,1) !Forward c2c FFT
iz=N9SEC/4
do i=1,iz
s(i)=real(c0(i))**2 + aimag(c0(i))**2
enddo
do i=1,4 !Smooth the spectrum a bit
call smo121(s,iz)
enddo
ia=nint((fsync-ftol)/df2)
ib=nint((fsync+ftol)/df2)
ipk=maxloc(s(ia:ib))
i0=ipk(1) + ia - 1
f2=df2*i0-750.0 ! f2 is the offset from nominal 750 Hz.
ia=nint(i0-baud/df2)
ib=nint(i0+baud/df2)
s1=0.0
s0=0.0
do i=ia,ib
s0=s0+s(i)
s1=s1+(i-i0)*s(i)
enddo
delta=s1/s0
i0=nint(i0+delta)
f2=i0*df2-750.0
c1=0.
ia=nint(i0-baud/df2)
ib=nint(i0+baud/df2)
do i=ia,ib
j=i-i0
if(j.ge.0) c1(j)=c0(i)
if(j.lt.0) c1(j+NZ)=c0(i)
enddo
call four2a(c1,NZ,1,1,1) !Reverse c2c FFT: back to time domain
c1sum(0)=c1(0)
do i=1,NZ-1
c1sum(i)=c1sum(i-1) + c1(i)
enddo
nspsd=1024/NDOWN
dt=NDOWN/12000.0
lagmax=1.5/dt
i0=nint(0.5*fsample/NDOWN) !Nominal start time is 0.5 s
pmax=0.
lagpk=0
do lag=-lagmax,lagmax
sp=0.
do j=1,24
i1=i0 + (isync(j)-1)*nspsd + lag
i2=i1 + nspsd
if(i1.lt.0 .or. i1.gt.NZ-1) cycle
if(i2.lt.0 .or. i2.gt.NZ-1) cycle
z=c1sum(i2)-c1sum(i1)
sp=sp + real(z)**2 + aimag(z)**2
enddo
if(sp.gt.pmax) then
pmax=sp
lagpk=lag
endif
p(lag)=sp
enddo
t2=lagpk*dt
snrsync=0.
sp=0.
sq=0.
nsum=0
tsym=1024/12000.0
do lag=-lagmax,lagmax
t=(lag-lagpk)*dt
if(abs(t).lt.tsym) cycle
nsum=nsum+1
sp=sp + p(lag)
sq=sq + p(lag)*p(lag)
enddo
ave=sp/nsum
rms=sqrt(sq/nsum-ave*ave)
snrsync=(pmax-ave)/rms
return
end subroutine qpc_sync

View File

@ -1,28 +0,0 @@
FUNCTION ran1(idum)
INTEGER idum,IA,IM,IQ,IR,NTAB,NDIV
REAL ran1,AM,EPS,RNMX
PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836, &
NTAB=32,NDIV=1+(IM-1)/NTAB,EPS=1.2e-7,RNMX=1.-EPS)
INTEGER j,k,iv(NTAB),iy
SAVE iv,iy
DATA iv /NTAB*0/, iy /0/
if (idum.le.0.or.iy.eq.0) then
idum=max(-idum,1)
do j=NTAB+8,1,-1
k=idum/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum=idum+IM
if (j.le.NTAB) iv(j)=idum
enddo
iy=iv(1)
endif
k=idum/IQ
idum=IA*(idum-k*IQ)-IR*k
if (idum.lt.0) idum=idum+IM
j=1+iy/NDIV
iy=iv(j)
iv(j)=idum
ran1=min(AM*iy,RNMX)
return
END FUNCTION ran1

View File

@ -1,17 +0,0 @@
subroutine sfox_ana(dd,npts,c0,npts2)
real dd(npts) !Raw data at 12000 Hz
complex c0(0:npts2-1) !Complex data at 12000 Hz
save
nfft1=npts
nfft2=nfft1
fac=2.0/(32767.0*nfft1)
c0(0:npts-1)=fac*dd(1:npts)
call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT
c0(nfft2/2+1:nfft2-1)=0. !Remove negative frequencies
c0(0)=0.5*c0(0) !Scale the DC term to 1/2
call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT; c0 is analytic sig
return
end subroutine sfox_ana

View File

@ -1,92 +0,0 @@
subroutine sfox_assemble(ntype,k,msg,mycall0,mygrid0,line)
! In subsequent calls, assemble all necessary information for a SuperFox
! transmission.
character*120 line
character*26 msg
character*26 msg0,msg1,msg2(5),msg3(5)
character*4 rpt2(5)
character*6 hiscall(10)
character*13 mycall0,mycall
character*4 mygrid0,mygrid
integer ntype !Message type: 0 Free Text
! 1 CQ MyCall MyGrid
! 2 Call_1 MyCall RR73
! 3 Call_1 MyCall rpt
integer nmsg(0:3) !Number of messages of type ntype
data nmsg/0,0,0,0/,nbits/0/,ntx/0/,nb_mycall/0/
save
if(mycall0(1:1).ne.' ') mycall=mycall0
if(mygrid0(1:1).ne.' ') mygrid=mygrid0
if(ntype.ge.1) nb_mycall=28 !### Allow for nonstandard MyCall ###
if(sum(nmsg).eq.0) then
hiscall=' '
rpt2=' '
endif
if(k.le.10) then
if(ntype.eq.0) then
if(nbits+nb_mycall.le.191) then !Enough room for a free text message?
nmsg(ntype)=nmsg(ntype)+1
nbits=nbits+142
msg0=msg
endif
else if(ntype.eq.1) then
if(nbits+nb_mycall.le.318) then !Enough room for a CQ ?
nmsg(ntype)=nmsg(ntype)+1
nbits=nbits+15
msg1=msg
endif
else if(ntype.eq.2) then
if(nbits+nb_mycall.le.305) then !Enough room for a RR73 message?
nmsg(ntype)=nmsg(ntype)+1
nbits=nbits+28
j=nmsg(ntype)
msg2(j)=msg
i1=index(msg,' ')
hiscall(j+5)=msg(1:i1-1)
endif
else if(ntype.eq.3) then
if(nbits+nb_mycall.le.300) then !Enough room for a message with report?
nmsg(ntype)=nmsg(ntype)+1
nbits=nbits+33
j=nmsg(ntype)
msg3(j)=msg
i1=index(msg,' ')
hiscall(j)=msg(1:i1-1)
i1=max(index(msg,'-'),index(msg,'+'))
rpt2(j)=msg(i1:i1+3)
endif
endif
return
endif
if(k.ge.11) then
! All pieces are now available. Put them into a command line for external
! program sfox_tx.
ntx=ntx+1 !Transmission number
nbits=nbits+nb_mycall !Add bits for MyCall
if(nmsg(1).ge.1) then
line=msg1
else
line=trim(mycall)
do i=1,nmsg(3)
line=trim(line)//' '//trim(hiscall(i))//' '//rpt2(i)
enddo
do i=1,nmsg(2)
line=trim(line)//' '//trim(hiscall(i+5))
enddo
endif
nmsg=0
nbits=0
nb_mycall=0
hiscall=' '
rpt2=' '
endif
return
end subroutine sfox_assemble

View File

@ -1,79 +0,0 @@
subroutine sfox_demod(crcvd,f,t,isync,s2,s3)
use sfox_mod
complex crcvd(NMAX) !Signal as received
complex c(0:NSPS-1) !Work array, one symbol long
real s2(0:NQ-1,0:151) !Symbol spectra, including sync
real s3(0:NQ-1,0:NN) !Synchronized symbol spectra
integer isync(24)
integer ipk(1)
integer hist1(0:NQ-1),hist2(0:NQ-1)
j0=nint(12000.0*(t+0.5))
df=12000.0/NSPS
i0=nint(f/df)-NQ/2
k2=0
s2(:,0)=0. !The punctured symbol
s3(:,0)=0. !The punctured symbol
do n=1,NDS !Loop over all symbols
jb=n*NSPS + j0
ja=jb-NSPS+1
k2=k2+1
if(ja.lt.1 .or. jb.gt.NMAX) cycle
c=crcvd(ja:jb)
call four2a(c,NSPS,1,-1,1) !Compute symbol spectrum
do i=0,NQ-1
s2(i,k2)=real(c(i0+i))**2 + aimag(c(i0+i))**2
enddo
enddo
call pctile(s2,NQ*151,50,base2)
s2=s2/base2
hist1=0
hist2=0
do j=0,151
ipk=maxloc(s2(1:NQ-1,j)) !Find the spectral peak
i=ipk(1)-1
hist1(i)=hist1(i)+1
enddo
hist1(0)=0 !Don't treat sync tone as a birdie
do i=0,123
hist2(i)=sum(hist1(i:i+3))
enddo
ipk=maxloc(hist1)
i1=ipk(1)-1
m1=maxval(hist1)
ipk=maxloc(hist2)
i2=ipk(1)-1
m2=maxval(hist2)
if(m1.gt.12) then
do i=0,127
if(hist1(i).gt.12) then
s2(i,:)=1.0
endif
enddo
endif
if(m2.gt.20) then
if(i2.ge.1) i2=i2-1
if(i2.gt.120) i2=120
s2(i2:i2+7,:)=1.0
endif
k3=0
do n=1,NDS !Copy symbol spectra from s2 into s3
if(any(isync(1:NS).eq.n)) cycle !Skip the sync symbols
k3=k3+1
s3(:,k3)=s2(:,n)
enddo
call pctile(s3,NQ*NN,50,base3)
s3=s3/base3
return
end subroutine sfox_demod

View File

@ -1,86 +0,0 @@
subroutine sfox_gen_gfsk(idat,f0,isync,itone,cdat)
parameter (NSPS=1024)
parameter (NDS=151)
parameter (NN=127) !NN = number of code symbols
parameter (NS=24) !NS = number of sync symbols
parameter (NMAX=15*12000)
parameter (NPTS=(NDS+2)*NSPS) !# of samples in waveform at 12000 samples/sec
parameter (BT=8) !GFSK time-bandwidth product
complex cdat(NMAX)
complex w, wstep
integer idat(NN)
integer isync(NS)
integer itone(NDS)
real*8 dt,twopi,phi,dphi_peak
real*8 dphi(0:NPTS-1)
real pulse(3*NSPS)
logical first/.true./
save first,twopi,dt,hmod,dphi_peak,pulse
if(first) then
twopi=8.d0*atan(1.0)
fsample=12000.0
dt=1.0/fsample
hmod=1.0
dphi_peak=twopi*hmod/real(NSPS)
do i=1,3*NSPS
tt=(i-1.5*NSPS)/real(NSPS)
pulse(i)=gfsk_pulse(BT,tt)
enddo
first=.false.
endif
wave=0.
! Create the itone sequence: data symbols and interspersed sync symbols
j=1
k=0
do i=1,NDS
if(j.le.NS .and. i.eq.isync(j)) then
if(j.lt.NS) j=j+1 !Index for next sync symbol
itone(i)=0 !Insert sync symbol at tone 0
else
k=k+1
itone(i)=idat(k) + 1 !Symbol value 0 is transmitted at tone 1, etc.
endif
enddo
! Generate the SuperFox waveform.
dphi=0.d0
do j=1,NDS
ib=(j-1)*NSPS
ie=ib+3*NSPS-1
dphi(ib:ie)=dphi(ib:ie)+dphi_peak*pulse(1:3*NSPS)*itone(j)
enddo
dphi(0:2*NSPS-1)=dphi(0:2*NSPS-1)+dphi_peak*itone(1)*pulse(NSPS+1:3*NSPS)
dphi(NDS*NSPS:(NDS+2)*NSPS-1)=dphi(NDS*NSPS:(NDS+2)*NSPS-1)+dphi_peak*itone(NDS)*pulse(1:2*NSPS)
phi=0.d0
dphi=dphi+twopi*f0*dt
k=0
do j=1,NSPS*(NDS+2)-1
k=k+1
cdat(k)=cmplx(cos(phi),sin(phi))
phi=phi+dphi(j)
enddo
! Add raised cosine ramps at the beginning and end of the waveform.
! Since the modulator expects an integral number of symbols, dummy
! symbols are added to the beginning and end of the waveform to
! hold the ramps. All but nramp of the samples in each dummy
! symbol will be zero.
nramp=NSPS/BT
cdat(1:NSPS-nramp)=cmplx(0.0,0.0)
cdat(NSPS-nramp+1:NSPS)=cdat(NSPS-nramp+1:NSPS) * &
(1.0-cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0
k1=(NDS+1)*NSPS+1
cdat(k1:k1+nramp-1)=cdat(k1:k1+nramp-1) * &
(1.0+cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0
cdat(k1+nramp:NPTS)=0.0
return
end subroutine sfox_gen_gfsk

View File

@ -1,73 +0,0 @@
module sfox_mod
parameter (NMAX=15*12000) !Samples in iwave (180,000)
integer MM,NQ,NN,KK,NS,NDS,NFZ,NSPS,NSYNC,NZ,NFFT1
real baud,tsym,bw
contains
subroutine sfox_init(mm0,nn0,kk0,itu,fspread,delay,fsample,ns0)
character*2 itu
integer isps(54)
integer iloc(1)
data isps/ 896, 960, 972, 980,1000,1008,1024,1029,1050,1080, &
1120,1125,1134,1152,1176,1200,1215,1225,1250,1260, &
1280,1296,1323,1344,1350,1372,1400,1440,1458,1470, &
1500,1512,1536,1568,1575,1600,1620,1680,1701,1715, &
1728,1750,1764,1792,1800,1875,1890,1920,1944,1960, &
2000,2016,2025,2048/
MM=mm0 !Bits per symbol
NQ=2**MM !Q, number of MFSK tones
NN=nn0 !Codeword length
KK=kk0 !Number of information symbols
NS=ns0 !Number of sync symbols
NDS=NN+NS !Total number of channel symbols
NFZ=3 !First zero
jsps=nint(12.8*fsample/NDS)
iloc=minloc(abs(isps-jsps))
NSPS=isps(iloc(1)) !Samples per symbol
NSYNC=NS*NSPS !Samples in sync waveform
NZ=NSPS*NDS !Samples in full Tx waveform
NFFT1=2*NSPS !Length of FFTs for symbol spectra
baud=fsample/NSPS
tsym=1.0/baud
bw=NQ*baud
fspread=0.0
delay=0.0
if(itu.eq.'LQ') then
fspread=0.5
delay=0.5
else if(itu.eq.'LM') then
fspread=1.5
delay=2.0
else if(itu.eq.'LD') then
fspread=10.0
delay=6.0
else if(itu.eq.'MQ') then
fspread=0.1
delay=0.5
else if(itu.eq.'MM') then
fspread=0.5
delay=1.0
else if(itu.eq.'MD') then
fspread=1.0
delay=2.0
else if(itu.eq.'HQ') then
fspread=0.5
delay=1.0
else if(itu.eq.'HM') then
fspread=10.0
delay=3.0
else if(itu.eq.'HD') then
fspread=30.0
delay=7.0
endif
return
end subroutine sfox_init
end module sfox_mod

View File

@ -1,178 +0,0 @@
subroutine sfox_pack(line,ckey,bMoreCQs,bSendMsg,freeTextMsg,xin)
use qpc_mod
use packjt
use packjt77
use julian
parameter (NQU1RKS=203514677)
integer*8 n47,n58,now
integer*1 xin(0:49) !Packed message as 7-bit symbols
logical*1 bMoreCQs,bSendMsg
logical text,allz
character*120 line !SuperFox message pieces
character*10 ckey
character*26 freeTextMsg
character*13 w(16)
character*11 c11
character*329 msgbits !Packed message as bits
character*38 c
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
i0=index(line,'/')
i3=0 !Default to i3=0, standard message
nh1=0 !Number of Hound calls with RR73
nh2=0 !Number of Hound calls with report
! Split the command line into words
w=' '
i1=1
do j=1,16
do i=i1,min(i1+12,120)
if(line(i:i).eq.' ') exit
enddo
i2=i-1
w(j)=line(i1:i2)
do i=i2+1,120
if(line(i:i).ne.' ') exit
enddo
i1=i
if(i1.ge.120) exit
enddo
nwords=j
do i=1,nwords
if(w(i)(1:1).eq.' ') then
nwords=i-1
exit
endif
enddo
do i=1,329 !Set all msgbits to '0'
msgbits(i:i)='0'
enddo
now=itime8()/30
now=30*now
read(ckey(5:10),*) notp
write(msgbits(307:326),'(b20.20)') notp !Insert the digital signature
if(w(1)(1:3).eq.'CQ ') then
i3=3
c11=w(2)(1:11)
n58=0
do i=1,11
n58=n58*38 + index(c,c11(i:i)) - 1
enddo
write(msgbits(1:58),'(b58.58)') n58
call packgrid(w(3)(1:4),n15,text)
write(msgbits(59:73),'(b15.15)') n15
write(msgbits(327:329),'(b3.3)') i3 !Message type i3=3
go to 800
endif
call pack28(w(1),n28) !Fox call
write(msgbits(1:28),'(b28.28)') n28
! Default report is RR73 if we're also sending a free text message.
if(bSendMsg) msgbits(141:160)='11111111111111111111'
j=29
! Process callsigns with RR73
do i=2,nwords
if(w(i)(1:1).eq.'+' .or. w(i)(1:1).eq.'-') cycle !Skip report words
i1=min(i+1,nwords)
if(w(i1)(1:1) .eq.'+' .or. w(i1)(1:1).eq.'-') cycle !Skip if i+1 is report
call pack28(w(i),n28)
write(msgbits(j:j+27),1002) n28 !Insert this call for RR73 message
1002 format(b28.28)
j=j+28
nh1=nh1+1
if(nh1.ge.5) exit !At most 5 RR73 callsigns
enddo
! Process callsigns with a report
j=169
j2=281
if(bSendMsg) then
i3=2
j=29 + 28*nh1
j2=141 + 5*nh1
endif
do i=2,nwords
i1=min(i+1,nwords)
if(w(i1)(1:1).eq.'+' .or. w(i1)(1:1).eq.'-') then
call pack28(w(i),n28)
write(msgbits(j:j+27),1002) n28 !Insert this call
read(w(i1),*) n !Valid reports are -18 to +12, plus RR73
if(n.lt.-18) n=-18 !... Even numbers only ...
if(n.gt.12) n=12
write(msgbits(j2:j2+4),1000) n+18
1000 format(b5.5)
w(i1)=""
nh2=nh2+1
! print*,'C',i3,i,j,n,w(i)
if( nh2.ge.4 .or. (nh1+nh2).ge.9 ) exit ! At most 4 callsigns w/reports
j=j+28
j2=j2+5
endif
enddo
800 if(bSendMsg) then
i1=26
do i=1,26
if(freeTextMsg(i:i).ne.' ') i1=i
enddo
do i=i1+1,26
freeTextMsg(i:i)='.'
enddo
if(i3.eq.3) then
call packtext77(freeTextMsg(1:13),msgbits(74:144))
call packtext77(freeTextMsg(14:26),msgbits(145:215))
elseif(i3.eq.2) then
call packtext77(freeTextMsg(1:13),msgbits(161:231))
call packtext77(freeTextMsg(14:26),msgbits(232:302))
endif
write(msgbits(327:329),'(b3.3)') i3 !Message type i3=2
endif
if(bMoreCQs) msgbits(306:306)='1'
read(msgbits(327:329),'(b3)') i3
if(i3.eq.0) then
do i=1,9
i0=i*28 + 1
read(msgbits(i0:i0+27),'(b28)') n28
if(n28.eq.0) write(msgbits(i0:i0+27),'(b28.28)') NQU1RKS
enddo
else if(i3.eq.3) then
allz=.true.
do i=0,6
i0=i*32 + 74
read(msgbits(i0:i0+31),'(b32)') n32
if(n32.ne.0) allz=.false.
enddo
if(allz) then
do i=0,6
i0=i*32 + 74
write(msgbits(i0:i0+31),'(b32.32)') NQU1RKS
enddo
endif
endif
read(msgbits,1004) xin(0:46)
1004 format(47b7)
mask21=2**21 - 1
n47=47
ncrc21=iand(nhash2(xin,n47,571),mask21) !Compute 21-bit CRC
xin(47)=ncrc21/16384 !First 7 of 21 bits
xin(48)=iand(ncrc21/128,127) !Next 7 bits
xin(49)=iand(ncrc21,127) !Last 7 bits
xin=xin(49:0:-1) !Reverse the symbol order
! NB: CRC is now in first three symbols, fox call in the last four.
return
end subroutine sfox_pack

View File

@ -1,55 +0,0 @@
subroutine sfox_prob(s3,rxdat,rxprob,rxdat2,rxprob2)
! Demodulate the 64-bin spectra for each of 63 symbols in a frame.
! Parameters
! rxdat most reliable symbol value
! rxdat2 second most likely symbol value
! rxprob probability that rxdat was the transmitted value
! rxprob2 probability that rxdat2 was the transmitted value
use sfox_mod
implicit real*8 (a-h,o-z)
real*4 s3(0:NQ-1,0:NN-1)
integer rxdat(0:NN-1),rxprob(0:NN-1),rxdat2(0:NN-1),rxprob2(0:NN-1)
afac=1.1
! scale=255.999
scale=2047.999
! Compute average spectral value
ave=sum(s3)/(NQ*ND)
i1=1 !Silence warning
i2=1
! Compute probabilities for most reliable symbol values
do j=0,NN-1 !Loop over all symbols
s1=-1.e30
psum=0.
do i=0,NQ-1 !Loop over frequency bins
x=min(afac*s3(i,j)/ave,50.d0)
psum=psum+s3(i,j)
if(s3(i,j).gt.s1) then
s1=s3(i,j) !Find max signal+noise power
i1=i !Find most reliable symbol value
endif
enddo
if(psum.eq.0.0) psum=1.e-6 !Guard against zero signal+noise
s2=-1.e30
do i=0,NQ-1
if(i.ne.i1 .and. s3(i,j).gt.s2) then
s2=s3(i,j) !Second largest signal+noise power
i2=i !Bin number for second largest power
endif
enddo
p1=s1/psum !p1, p2 are symbol metrics for ftrsd
p2=s2/psum
rxdat(j)=i1
rxdat2(j)=i2
rxprob(j)=scale*p1 !Scaled probabilities, 0 - 255
rxprob2(j)=scale*p2
enddo
return
end subroutine sfox_prob

View File

@ -1,213 +0,0 @@
subroutine sfox_remove_ft8(dd,npts)
use packjt77
include 'ft8_params.f90'
parameter (MAXCAND=100)
parameter (NP2=2812)
integer itone(NN)
integer iloc(1), ip(1)
integer icos7(0:6)
integer graymap(0:7)
integer*1 cw(174),apmask(174)
integer*1 message91(91)
integer*1 message77(77)
character*77 c77
character*37 msg37
real s8(0:7,NN)
real s2(0:7)
real ss(9)
real candidate(3,MAXCAND)
real sbase(NH1)
real dd(npts)
real bmeta(174),bmetd(174)
real llra(174),llrd(174)
complex cd0(0:3199)
complex csymb(32)
complex ctwk(32)
complex cs(0:7,NN)
data icos7/3,1,4,0,6,5,2/
logical first,newdat
logical one(0:7,0:2)
logical unpk77_success
data first/.true./
data graymap/0,1,3,2,5,6,4,7/
save one,first,twopi
if(first) then
one=.false.
do i=0,7
do j=0,2
if(iand(i,2**j).ne.0) one(i,j)=.true.
enddo
enddo
first=.false.
twopi=8.0*atan(1.0)
endif
fs2=12000.0/NDOWN
dt2=1.0/fs2
nfa=500
nfb=2500
syncmin=1.5
nfqso=750
call sync8(dd,npts,nfa,nfb,syncmin,nfqso,MAXCAND,candidate,ncand,sbase)
newdat=.true.
do icand=1,ncand
f1=candidate(1,icand)
xdt=candidate(2,icand)
xbase=10.0**(0.1*(sbase(nint(f1/3.125))-40.0))
call ft8_downsample(dd,newdat,f1,cd0)
newdat=.false.
i0=nint((xdt+0.5)*fs2)
smax=0.0
do idt=i0-10,i0+10
call sync8d(cd0,idt,ctwk,0,sync)
if(sync.gt.smax) then
smax=sync
ibest=idt
endif
enddo
smax=0.0
delfbest=0.0
do ifr=-5,5 !Search over +/- 2.5 Hz
delf=ifr*0.5
dphi=twopi*delf*dt2
phi=0.0
do i=1,32
ctwk(i)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dphi,twopi)
enddo
call sync8d(cd0,ibest,ctwk,1,sync)
if( sync .gt. smax ) then
smax=sync
delfbest=delf
endif
enddo
f1=f1+delfbest !Improved estimate of DF
call ft8_downsample(dd,newdat,f1,cd0) !Mix f1 to baseband and downsample
smax=0.0
do idt=-4,4 !Search over +/- one quarter symbol
call sync8d(cd0,ibest+idt,ctwk,0,sync)
ss(idt+5)=sync
enddo
smax=maxval(ss)
iloc=maxloc(ss)
ibest=iloc(1)-5+ibest
xdt=(ibest-1)*dt2
sync=smax
do k=1,NN
i1=ibest+(k-1)*32
csymb=cmplx(0.0,0.0)
if( i1.ge.0 .and. i1+31 .le. NP2-1 ) csymb=cd0(i1:i1+31)
call four2a(csymb,32,1,-1,1)
cs(0:7,k)=csymb(1:8)/1e3
s8(0:7,k)=abs(csymb(1:8))
enddo
! sync quality check
is1=0
is2=0
is3=0
do k=1,7
ip=maxloc(s8(:,k))
if(icos7(k-1).eq.(ip(1)-1)) is1=is1+1
ip=maxloc(s8(:,k+36))
if(icos7(k-1).eq.(ip(1)-1)) is2=is2+1
ip=maxloc(s8(:,k+72))
if(icos7(k-1).eq.(ip(1)-1)) is3=is3+1
enddo
! hard sync sum - max is 21
nsync=is1+is2+is3
if(nsync .le. 6) then ! bail out
nbadcrc=1
cycle
endif
nsym=1
nt=2**(3*nsym)
do ihalf=1,2
do k=1,29,nsym
if(ihalf.eq.1) ks=k+7
if(ihalf.eq.2) ks=k+43
amax=-1.0
do i=0,nt-1
i3=iand(i,7)
s2(i)=abs(cs(graymap(i3),ks))
enddo
i32=1+(k-1)*3+(ihalf-1)*87
ibmax=2
do ib=0,ibmax
bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - &
maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib))
if(i32+ib .gt.174) cycle
bmeta(i32+ib)=bm
den=max(maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)), &
maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib)))
if(den.gt.0.0) then
cm=bm/den
else ! erase it
cm=0.0
endif
bmetd(i32+ib)=cm
enddo
enddo
enddo
call normalizebmet(bmeta,174)
call normalizebmet(bmetd,174)
scalefac=2.83
llra=scalefac*bmeta
llrd=scalefac*bmetd
cw=0
dmin=0
norder=2
maxosd=-1
Keff=91
apmask=0
message91=0
cw=0
call decode174_91(llra,Keff,maxosd,norder,apmask,message91,cw, &
ntype,nharderrors,dmin)
if(nharderrors.ge.0) then
message77=message91(1:77)
else
cycle
endif
if(count(cw.eq.0).eq.174) cycle
write(c77,'(77i1)') message77
read(c77(72:74),'(b3)') n3
read(c77(75:77),'(b3)') i3
if(i3.gt.5 .or. (i3.eq.0.and.n3.gt.6)) cycle
if(i3.eq.0 .and. n3.eq.2) cycle
call unpack77(c77,1,msg37,unpk77_success)
! write(77,*) 'FT8 interference: ',msg37
if(.not.unpk77_success) cycle
! Message structure: S7 D29 S7 D29 S7
itone(1:7)=icos7
itone(36+1:36+7)=icos7
itone(NN-6:NN)=icos7
k=7
do j=1,ND
i=3*j -2
k=k+1
if(j.eq.30) k=k+7
indx=cw(i)*4 + cw(i+1)*2 + cw(i+2)
itone(k)=graymap(indx)
enddo
call subtractft8(dd,itone,f1,xdt,.true.)
! return
enddo
return
end subroutine sfox_remove_ft8

View File

@ -1,95 +0,0 @@
subroutine sfox_remove_tone(c0,fsync)
parameter (NMAX=15*12000)
parameter (NFILT=8000)
complex c0(NMAX)
complex cwindow(15*12000)
complex cref(NMAX)
complex cfilt(NMAX)
real window(-NFILT/2:NFILT/2)
! real endcorrection(NFILT/2+1)
real s(NMAX/4)
integer ipk(1)
logical first
data first/.true./
save cwindow,first,pi
if(first) then
pi=4.0*atan(1.0)
fac=1.0/float(NMAX)
sumw=0.0
do j=-NFILT/2,NFILT/2
window(j)=cos(pi*j/NFILT)**2
sumw=sumw+window(j)
enddo
cwindow=0.
cwindow(1:NFILT+1)=window/sumw
cwindow=cshift(cwindow,NFILT/2+1)
call four2a(cwindow,NMAX,1,-1,1)
cwindow=cwindow*fac ! frequency domain smoothing filter
first=.false.
endif
fsample=12000.0
baud=fsample/1024.0
df=fsample/NMAX
fac=1.0/NMAX
do it=1,1 ! Remove 1 tone, if present
cfilt=fac*c0
call four2a(cfilt,NMAX,1,-1,1) ! fourier transform of input data
iz=NMAX/4
do i=1,iz
s(i)=real(cfilt(i))**2 + aimag(cfilt(i))**2
enddo
ia=nint((fsync-50.0)/df)
ib=nint((fsync+1500.0+50.0)/df)
ipk=maxloc(s(ia:ib))
i0=ipk(1) + ia - 1
nbaud=nint(baud/df)
ia=i0-nbaud
ib=i0+nbaud
s0=0.0
s1=0.0
s2=0.0
do i=ia,ib
s0=s0+s(i)
s1=s1+(i-i0)*s(i)
enddo
delta=s1/s0
i0=nint(i0+delta)
f2=i0*df
ia=i0-nbaud
ib=i0+nbaud
do i=ia,ib
s2=s2 + s(i)*(i-i0)**2
enddo
sigma=sqrt(s2/s0)*df
! write(*,*) 'frequency, spectral width ',f2,sigma
if(sigma .gt. 2.5) exit
! write(*,*) 'remove_tone - frequency: ',f2
dt=1.0/fsample
do i=1, NMAX
arg=2*pi*f2*i*dt
cref(i)=cmplx(cos(arg),sin(arg))
enddo
cfilt=c0*conjg(cref) ! baseband to be filtered
call four2a(cfilt,NMAX,1,-1,1)
cfilt=cfilt*cwindow
call four2a(cfilt,NMAX,1,1,1)
nframe=50*3456
do i=1,nframe
cref(i)=cfilt(i)*cref(i)
c0(i)=c0(i)-cref(i)
enddo
enddo
return
end subroutine sfox_remove_tone

View File

@ -1,119 +0,0 @@
subroutine sfox_unpack(nutc,x,nsnr,f0,dt0,foxcall,notp)
use packjt77
parameter (NQU1RKS=203514677)
integer*1 x(0:49)
integer*8 n58
logical success
character*336 msgbits
character*22 msg(10) !### only msg(1) is used ??? ###
character*13 foxcall,c13
character*10 ssignature
character*4 crpt(5),grid4
character*26 freeTextMsg
character*38 c
logical use_otp
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
ncq=0
if (notp.eq.0) then
use_otp = .FALSE.
else
use_otp = .TRUE.
endif
write(msgbits,1000) x(0:46)
1000 format(47b7.7)
read(msgbits(327:329),'(b6)') i3 !Message type
read(msgbits(1:28),'(b28)') n28 !Standard Fox call
call unpack28(n28,foxcall,success)
if(i3.eq.1) then !Compound Fox callsign
! read(msgbits(87:101),'(b15)') n15
! call unpackgrid(n15,grid4)
! msg(1)='CQ '//trim(foxcall)//' '//grid4
! write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(1))
! go to 100
else if(i3.eq.2) then !Up to 4 Hound calls and free text
call unpacktext77(msgbits(161:231),freeTextMsg(1:13))
call unpacktext77(msgbits(232:302),freeTextMsg(14:26))
do i=26,1,-1
if(freeTextMsg(i:i).ne.'.') exit
freeTextMsg(i:i)=' '
enddo
write(*,1100) nutc,nsnr,dt0,nint(f0),freeTextMsg
1100 format(i6.6,i4,f5.1,i5,1x,"~",2x,a)
else if(i3.eq.3) then !CQ FoxCall Grid
read(msgbits(1:58),'(b58)') n58 !FoxCall
do i=11,1,-1
j=mod(n58,38)+1
foxcall(i:i)=c(j:j)
n58=n58/38
enddo
foxcall(12:13)=' '
read(msgbits(59:73),'(b15)') n15
call unpackgrid(n15,grid4)
msg(1)='CQ '//trim(foxcall)//' '//grid4
write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(1))
read(msgbits(74:105),'(b32)') n32
if(n32.eq.NQU1RKS) go to 100
call unpacktext77(msgbits(74:144),freeTextMsg(1:13))
call unpacktext77(msgbits(145:215),freeTextMsg(14:26))
do i=26,1,-1
if(freeTextMsg(i:i).ne.'.') exit
freeTextMsg(i:i)=' '
enddo
if(len(trim(freeTextMsg)).gt.0) write(*,1100) nutc,nsnr,dt0,&
nint(f0),freeTextMsg
go to 100
endif
j=281
iz=4 !Max number of reports
if(i3.eq.2) j=141
do i=1,iz !Extract the reports
read(msgbits(j:j+4),'(b5)') n
if(n.eq.31) then
crpt(i)='RR73'
else
write(crpt(i),1006) n-18
1006 format(i3.2)
if(crpt(i)(1:1).eq.' ') crpt(i)(1:1)='+'
endif
j=j+5
enddo
! Unpack Hound callsigns and format user-level messages:
iz=9 !Max number of hound calls
if(i3.eq.2 .or. i3.eq.3) iz=4
do i=1,iz
j=28*i + 1
read(msgbits(j:j+27),'(b28)') n28
call unpack28(n28,c13,success)
if(n28.eq.0 .or. n28.eq.NQU1RKS) cycle
msg(i)=trim(c13)//' '//trim(foxcall)
if(msg(i)(1:3).eq.'CQ ') then
ncq=ncq+1
else
if(i3.eq.2) then
msg(i)=trim(msg(i))//' '//crpt(i)
else
if(i.le.5) msg(i)=trim(msg(i))//' RR73'
if(i.gt.5) msg(i)=trim(msg(i))//' '//crpt(i-5)
endif
endif
if(ncq.le.1 .or. msg(i)(1:3).ne.'CQ ') then
write(*,1100) nutc,nsnr,dt0,nint(f0),trim(msg(i))
endif
enddo
if(msgbits(306:306).eq.'1' .and. ncq.lt.1) then
write(*,1100) nutc,nsnr,dt0,nint(f0),'CQ '//foxcall
endif
100 read(msgbits(307:326),'(b20)') notp
if (use_otp) then
write(ssignature,'(I6.6)') notp
write(*,1100) nutc,nsnr,dt0,nint(f0),'$VERIFY$ '//trim(foxcall)//' '//trim(ssignature)
endif
return
end subroutine sfox_unpack

View File

@ -1,40 +0,0 @@
subroutine sfox_wave(fname)
! Called by WSJT-X when it's time for SuperFox to transmit. Reads array
! itone(1:151) from disk file 'sfox_2.dat' in the writable data directory.
parameter (NWAVE=(160+2)*134400*4) !Max WSJT-X waveform (FST4-1800 at 48kHz)
parameter (NN=151,NSPS=1024)
character*(*) fname
integer itone(151)
real*8 dt,twopi,f0,baud,phi,dphi
common/foxcom/wave(NWAVE)
wave=0.
open(25,file=trim(fname),status='unknown',err=999)
read(25,'(20i4)',err=999,end=999) itone
close(25)
if(itone(1).lt.0 .or. itone(1).gt.128) go to 999
! Generate the SuperFox waveform.
dt=1.d0/48000.d0
twopi=8.d0*atan(1.d0)
f0=750.0d0
phi=0.d0
baud=12000.d0/NSPS
k=0
do j=1,NN
f=f0 + baud*mod(itone(j),128)
dphi=twopi*f*dt
do ii=1,4*NSPS
k=k+1
phi=phi+dphi
xphi=phi
wave(k)=sin(xphi)
enddo
enddo
999 return
end subroutine sfox_wave

View File

@ -1,77 +0,0 @@
subroutine sfox_wave_gfsk()
! Called by WSJT-X when it's time for SuperFox to transmit. Reads array
! itone(1:151) from disk file 'sfox_2.dat' in the writable data directory.
! Generates a GFSK waveform with short ramp-up and ramp-down symbols of
! duration NSPS/BT at the beginning and end of the waveform.
parameter (NWAVE=(160+2)*134400*4) !Max WSJT-X waveform (FST4-1800 at 48kHz)
parameter (NSYM=151,NSPS=1024*4)
parameter (NPTS=(NSYM+2)*NSPS)
parameter (BT=8)
character*40 cmsg2
integer itone(151)
real*8 dt,twopi,f0,phi,dphi_peak
real*8 dphi(0:NPTS-1)
real*8 pulse(3*NSPS)
logical first/.true./
common/foxcom/wave(NWAVE)
common/foxcom3/nslots2,cmsg2(5),itone3(151)
save first,twopi,dt,hmod,dphi_peak,pulse
if(first) then
fsample=48000.0
twopi=8.d0*atan(1.d0)
dt=1.d0/fsample
hmod=1.0
dphi_peak=twopi*hmod/real(NSPS)
do i=1,3*NSPS
tt=(i-1.5*NSPS)/real(NSPS)
pulse(i)=gfsk_pulse(BT,tt)
enddo
first=.false.
endif
wave=0.
itone=itone3
if(itone(1).lt.0 .or. itone(1).gt.128) go to 999
! Generate the SuperFox waveform.
dphi=0.d0
do j=1,NSYM
ib=(j-1)*NSPS
ie=ib+3*NSPS-1
dphi(ib:ie)=dphi(ib:ie)+dphi_peak*pulse(1:3*NSPS)*itone(j)
enddo
dphi(0:2*NSPS-1)=dphi(0:2*NSPS-1)+dphi_peak*itone(1)*pulse(NSPS+1:3*NSPS)
dphi(NSYM*NSPS:(NSYM+2)*NSPS-1)=dphi(NSYM*NSPS:(NSYM+2)*NSPS-1)+dphi_peak*itone(NSYM)*pulse(1:2*NSPS)
phi=0.d0
f0=750.0d0
dphi=dphi+twopi*f0*dt
k=0
do j=1,NSPS*(NSYM+2)-1
k=k+1
wave(k)=sin(phi)
phi=phi+dphi(j)
enddo
! Add raised cosine ramps at the beginning and end of the waveform.
! Since the modulator expects an integral number of symbols, dummy
! symbols are added to the beginning and end of the waveform to
! hold the ramps. All but nramp of the samples in each dummy
! symbol will be zero.
nramp=NSPS/BT
wave(1:NSPS-nramp)=0.0
wave(NSPS-nramp+1:NSPS)=wave(NSPS-nramp+1:NSPS) * &
(1.0-cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0
k1=(NSYM+1)*NSPS+1
wave(k1:k1+nramp-1)=wave(k1:k1+nramp-1) * &
(1.0+cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0
wave(k1+nramp:NPTS)=0.0
999 return
end subroutine sfox_wave_gfsk

View File

@ -1,164 +0,0 @@
program sfoxsim
! - Generate complex-valued SuperFox waveform, cdat.
! - Pass cdat through Watterson channel simulator
! - Add noise to the imaginary part of cdat and write to wav file.
use wavhdr
use qpc_mod
use sfox_mod
type(hdr) h !Header for .wav file
logical*1 bMoreCQs !Include a CQ when space available?
logical*1 bSendMsg !Send a Free text message
integer*2 iwave(NMAX) !Generated i*2 waveform
integer isync(24) !Indices of sync symbols
integer itone(151) !Symbol values, data and sync
integer*1 xin(0:49)
integer*1 y(0:127)
real*4 xnoise(NMAX) !Random noise
real*4 dat(NMAX) !Generated real data
complex cdat(NMAX) !Generated complex waveform
complex crcvd(NMAX) !Signal as received
real, allocatable :: s3(:,:) !Symbol spectra: will be s3(NQ,NN)
integer, allocatable :: msg0(:) !Information symbols
integer, allocatable :: chansym(:) !Encoded data, 7-bit integers
character fname*17,arg*12,channel*2,foxcall*11
character*10 ckey
character*26 text_msg
character*120 line !SuperFox message pieces
character*40 cmsg(5)
data ckey/'0000000000'/
data cmsg/'W0AAA RR73; W5FFF <K1JT> -18', &
'W1BBB RR73; W6GGG <K1JT> -15', &
'W2CCC RR73; W7HHH <K1JT> -12', &
'W3DDD RR73; W8III <K1JT> -09', &
'W4EEE RR73; W9JJJ <K1JT> -06'/
data text_msg/'0123456789ABCDEFGHIJKLMNOP'/
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80, &
83,84,86,89/
nargs=iargc()
if(nargs.ne.10) then
print*,'Usage: sfoxsim f0 DT Chan FoxC H1 H2 CQ FT nfiles snr'
print*,'Example: sfoxsim 750 0.0 MM K1JT 5 1 0 0 10 -15'
print*,' f0=0 to dither f0 and DT'
print*,' Chan Channel type AW LQ LM LD MQ MM MD HQ HM HD'
print*,' FoxC Fox callsign'
print*,' key'
print*,' H1 number of Hound calls with RR73'
print*,' H2 number of Hound calls with reports'
print*,' CQ=1 to include a CQ message'
print*,' FT=1 to include a Free Text message'
go to 999
endif
call getarg(1,arg)
read(arg,*) f0
call getarg(2,arg)
read(arg,*) xdt
call getarg(3,channel)
call getarg(4,foxcall)
call getarg(5,arg)
read(arg,*) nh1
call getarg(6,arg)
read(arg,*) nh2
call getarg(7,arg)
read(arg,*) ncq
bMoreCQs=ncq.ne.0
call getarg(8,arg)
read(arg,*) nft
bSendMsg=nft.ne.0
call getarg(9,arg)
read(arg,*) nfiles
call getarg(10,arg)
read(arg,*) snr
fspread=0.0
delay=0.0
fsample=12000.0 !Sample rate (Hz)
call sfox_init(7,127,50,channel,fspread,delay,fsample,24)
txt=(NN+NS)*NSPS/fsample
write(*,1000) f0,xdt,channel,snr
1000 format('sfoxsim: f0= ',f5.1,' dt= ',f4.2,' Channel: ',a2,' snr: ',f5.1,' dB')
! Allocate storage for arrays that depend on code parameters.
allocate(s3(0:NQ-1,0:NN-1))
allocate(msg0(1:KK))
allocate(chansym(0:NN-1))
if(nft.ne.0) then
open(10,file='text_msg.txt',status='old',err=2)
read(10,*) text_msg
endif
2 idum=-1
rms=100.
baud=fsample/nsps !Keying rate, 11.719 baud for nsps=1024
bandwidth_ratio=2500.0/fsample
do i=1,5
cmsg(i)=cmsg(i)(1:19)//trim(foxcall)//cmsg(i)(24:28)
if(i.gt.nh1 .and. i.gt.nh2) then
cmsg(i)=''
elseif(i.gt.nh1) then
cmsg(i)=cmsg(i)(13:18)//trim(foxcall)//cmsg(i)(25:28)
elseif(i.gt.nh2) then
cmsg(i)=cmsg(i)(1:6)//trim(foxcall)//' RR73'
endif
! write(*,*) 'Debug ',cmsg(i)
enddo
if((nh1+nh2).eq.0 .and. bMoreCQs) cmsg(1)='CQ '//trim(foxcall)//' FN20'
! Generate a SuperFox message
nslots=5
call foxgen2(nslots,cmsg,line,foxcall) !Parse old-style Fox messages
call sfox_pack(line,ckey,bMoreCQs,bSendMsg,text_msg,xin)
call qpc_encode(y,xin)
y=cshift(y,1)
y(127)=0
chansym=y(0:126)
sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snr)
sigr=sqrt(2.)*sig
if(snr.gt.90.0) sig=1.0
do ifile=1,nfiles
xnoise=0.
if(snr.lt.90) then
do i=1,NMAX
xnoise(i)=gran() !Gaussian noise
enddo
endif
f1=f0
if(f0.eq.0.0) then
f1=750 + 20.0*(ran1(idum)-0.5)
xdt=ran1(idum)-0.5
endif
! Generate cdat, the SuperFox waveform
call sfox_gen_gfsk(chansym,f1,isync,itone,cdat)
crcvd=0.
crcvd(1:NMAX)=cshift(cdat(1:NMAX),-nint((0.5+xdt)*fsample))
if(fspread.ne.0 .or. delay.ne.0) call watterson(crcvd,NMAX,NZ,fsample,&
delay,fspread)
dat=aimag(sigr*crcvd(1:NMAX)) + xnoise !Add generated AWGN noise
fac=32767.0
if(snr.ge.90.0) iwave(1:NMAX)=nint(fac*dat(1:NMAX))
if(snr.lt.90.0) iwave(1:NMAX)=nint(rms*dat(1:NMAX))
h=default_header(12000,NMAX)
fname='000000_000001.wav'
nsec=(ifile-1)*30
nhr=nsec/3600
nmin=(nsec-nhr*3600)/60
nsec=mod(nsec,60)
write(fname(8:13),'(3i2.2)') nhr,nmin,nsec
open(10,file=trim(fname),access='stream',status='unknown')
write(10) h,iwave(1:NMAX) !Save the .wav file
close(10)
enddo ! ifile
999 end program sfoxsim

View File

@ -1,59 +0,0 @@
program sfrx
! Command-line SuperFox decoder
use sfox_mod
use julian
integer*2 iwave(NMAX)
integer ihdr(11)
character*120 fname
include 'gtag.f90'
narg=iargc()
if(narg.lt.1) then
print*,'Usage: sfrx fsync ftol infile [...]'
print*,' sfrx 775 10 240811_102400.wav'
print*,'Reads one or more .wav files and calls SuperFox decoder on each.'
print '(" Git tag: ",z9)',ntag
go to 999
endif
call getarg(1,fname)
read(fname,*,err=1) fsync
call getarg(2,fname)
read(fname,*,err=1) ftol
nfqso=nint(fsync)
ntol=nint(ftol)
1 nf=0
nd=0
nv=0
do ifile=3,narg
call getarg(ifile,fname)
write(72,*) ifile,narg,fname
open(10,file=trim(fname),status='old',access='stream',err=4)
go to 5
4 print*,'Cannot open file ',trim(fname)
go to 999
5 read(10) ihdr,iwave
close(10)
nz=len(trim(fname))
nyymmdd=ihdr(1)
nutc=ihdr(2)
if(fname(nz-3:nz).eq.'.wav') then
read(fname(nz-16:nz-11),*) nyymmdd
read(fname(nz-9:nz-4),*) nutc
endif
call sfrx_sub(nyymmdd,nutc,nfqso,ntol,iwave)
nf=nf+1
enddo
999 end program sfrx

View File

@ -1,54 +0,0 @@
subroutine sfrx_sub(nyymmdd,nutc,nfqso,ntol,iwave)
use sfox_mod
use julian
integer*2 iwave(NMAX)
integer*8 secday,ntime8
integer*1 xdec(0:49)
character*13 foxcall
complex c0(NMAX) !Complex form of signal as received
real dd(NMAX)
logical crc_ok
data secday/86400/
fsync=nfqso
ftol=ntol
fsample=12000.0
call sfox_init(7,127,50,'no',fspread,delay,fsample,24)
npts=15*12000
if(nyymmdd.eq.-1) then
ntime8=itime8()/30
ntime8=30*ntime8
else
iyr=2000+nyymmdd/10000
imo=mod(nyymmdd/100,100)
iday=mod(nyymmdd,100)
ih=nutc/10000
im=mod(nutc/100,100)
is=mod(nutc,100)
ntime8=secday*(JD(iyr,imo,iday)-2440588) + 3600*ih + 60*im + is
endif
dd=iwave
call sfox_remove_ft8(dd,npts)
call sfox_ana(dd,npts,c0,npts)
call sfox_remove_tone(c0,fsync) ! Needs testing
ndepth=3
dth=0.5
damp=1.0
call qpc_decode2(c0,fsync,ftol, xdec,ndepth,dth,damp,crc_ok, &
snrsync,fbest,tbest,snr)
if(crc_ok) then
nsnr=nint(snr)
nsignature = 1
call sfox_unpack(nutc,xdec,nsnr,fbest-750.0,tbest,foxcall,nsignature)
endif
return
end subroutine sfrx_sub

View File

@ -1,107 +0,0 @@
program sftx
! This program is required in order to create a SuperFox transmission.
! The present version goes through the following steps:
! 1. Read old-style Fox messages from file 'sfox_1.dat' in the WSJT-X
! writable data directory.
! 2. Parse up to NSlots=5 messages to extract MyCall, up to 9 Hound
! calls, and the report or RR73 to be sent to each Hound.
! 3. Assemble and encode a single SuperFox message to produce itone(1:151),
! the array of channel symbol values.
! 4. Write the contents of array itone to file 'sfox_2.dat'.
use qpc_mod
use sfox_mod
character*120 fname !Corrected path for sfox_1.dat
character*120 line !List of SuperFox message pieces
character*40 cmsg(5) !Old-style Fox messages
character*26 freeTextMsg
character*2 arg
character*10 ckey
! character*9 foxkey
character*11 foxcall0,foxcall
logical*1 bMoreCQs,bSendMsg
logical crc_ok
real py(0:127,0:127) !Probabilities for received synbol values
integer*8 n47
integer itone(151) !SuperFox channel-symbol values
integer*1 xin(0:49) !Packed message as 7-bit symbols
integer*1 xdec(0:49) !Decoded message
integer*1 y(0:127) !Encoded symbols as i*1 integers
integer*1 ydec(0:127) !Decoded codeword
integer*1 yy(0:10)
integer chansym0(127) !Transmitted symbols, data only
integer chansym(127) !Received symbols, data only
integer isync(24) !Symbol numbers for sync tones
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80, &
83,84,86,89/
include 'gtag.f90'
narg=iargc()
if(narg.ne.3) then
print '(" Git tag: ",z9)',ntag
go to 999
endif
! sftx <message_file_name> <foxcall> <ckey>
call getarg(1,fname)
do i=1,len(trim(fname))
if(fname(i:i).eq.'\\') fname(i:i)='/'
enddo
call getarg(2,foxcall0)
call getarg(3,ckey)
! if((foxkey(foxcall0).ne.ckey).and.(INDEX(ckey,'OTP:').eq.0)) then ! neither kind
! itone=-99
! go to 100
! endif
fsample=12000.0
call sfox_init(7,127,50,'no',fspread,delay,fsample,24)
open(25,file=trim(fname),status='unknown')
do i=1,5
read(25,1000,end=10) cmsg(i)
1000 format(a40)
enddo
i=6
10 close(25)
nslots=i-1
freeTextMsg=' '
bMoreCQs=cmsg(1)(40:40).eq.'1'
bSendMsg=cmsg(nslots)(39:39).eq.'1'
if(bSendMsg) then
freeTextMsg=cmsg(nslots)(1:26)
if(nslots.gt.2) nslots=2
endif
call foxgen2(nslots,cmsg,line,foxcall) !Parse old-style Fox messages
! Pack message information and CRC into xin(0:49)
call sfox_pack(line,ckey,bMoreCQs,bSendMsg,freeTextMsg,xin)
call qpc_encode(y,xin) !Encode the message to 128 symbols
y=cshift(y,1) !Puncture the code by removing y(0)
y(127)=0
chansym0=y(0:126)
! Create the full itone sequence containing both data and sync symbols
j=1
k=0
do i=1,NDS
if(j.le.NS .and. i.eq.isync(j)) then
if(j.lt.NS) j=j+1 !Index for next sync symbol
itone(i)=0 !Insert sync symbol at tone 0
else
k=k+1
itone(i)=chansym0(k) + 1 !Symbol value 0 transmitted as tone 1, etc.
endif
enddo
100 i1=max(index(fname,'sfox_1'),1)
fname(i1:i1+9)='sfox_2.dat'
open(25,file=trim(fname),status='unknown')
write(25,1100) itone
1100 format(20i4)
close(25)
999 end program sftx

View File

@ -1,65 +0,0 @@
subroutine sftx_sub(ckey0)
! This routine is required in order to create a SuperFox transmission.
! The present version goes through the following steps:
! 1. Read old-style Fox messages from file 'sfox_1.dat' in the WSJT-X
! writable data directory.
! 2. Parse up to NSlots=5 messages to extract MyCall, up to 9 Hound
! calls, and the report or RR73 to be sent to each Hound.
! 3. Assemble and encode a single SuperFox message to produce itone(1:151),
! the array of channel symbol values.
! 4. Write the contents of array itone to file 'sfox_2.dat'.
use qpc_mod
use sfox_mod
character*120 line !List of SuperFox message pieces
character*40 cmsg !Old-style Fox messages
character*26 freeTextMsg
character*(*) ckey0
character*10 ckey
character*11 foxcall
logical*1 bMoreCQs,bSendMsg
integer*1 xin(0:49) !Packed message as 7-bit symbols
integer*1 y(0:127) !Encoded symbols as i*1 integers
integer chansym0(127) !Transmitted symbols, data only
integer isync(24) !Symbol numbers for sync tones
common/foxcom3/nslots,cmsg(5),itone(151)
data isync/1,2,4,7,11,16,22,29,37,39,42,43,45,48,52,57,63,70,78,80, &
83,84,86,89/
ckey=ckey0
fsample=12000.0
call sfox_init(7,127,50,'no',fspread,delay,fsample,24)
freeTextMsg=' '
bMoreCQs=cmsg(1)(40:40).eq.'1'
bSendMsg=cmsg(nslots)(39:39).eq.'1'
if(bSendMsg) then
freeTextMsg=cmsg(nslots)(1:26)
if(nslots.gt.4) nslots=4
endif
call foxgen2(nslots,cmsg,line,foxcall) !Parse old-style Fox messages
! Pack message information and CRC into xin(0:49)
call sfox_pack(line,ckey,bMoreCQs,bSendMsg,freeTextMsg,xin)
call qpc_encode(y,xin) !Encode the message to 128 symbols
y=cshift(y,1) !Puncture the code by removing y(0)
y(127)=0
chansym0=y(0:126)
! Create the full itone sequence containing both data and sync symbols
j=1
k=0
do i=1,NDS
if(j.le.NS .and. i.eq.isync(j)) then
if(j.lt.NS) j=j+1 !Index for next sync symbol
itone(i)=0 !Insert sync symbol at tone 0
else
k=k+1
itone(i)=chansym0(k) + 1 !Symbol value 0 transmitted as tone 1, etc.
endif
enddo
end subroutine sftx_sub

View File

@ -1,66 +0,0 @@
Bit packing of SuperFox QPC Messages
-----------------------------------------------------------------------------
The IV3NWV Q-ary Polar Code has parameters (n,k) = (127,50). The last
three 7-bit information symbols convey a 21-bit CRC based on the first
47 symbols. Thus, each Super Fox transmission carries a payload of
47*7=329 bits. On a modern x86 processor the decoder executes in
deterministic time around 5 ms per decode, and always produces a
result. The CRC test rejects all but around 1 in two million false
decodes.
Bit fields are labeled with tags as defined in the QEX article "The
FT4 and FT8 Communication Protocols" by Franke, Somerville, and Taylor
in QEX for July/August 2020, available on the WSJT web site here:
https://wsjt.sourceforge.io/FT4_FT8_QEX.pdf. As one example, the tag
'c28' denotes a standard callsign, which requires 28 bits.
=============================================================================
i3 = 0: Standard message: FoxCall, up to 9 HoundCalls, up to 4 signal
reports, "MoreCQs" flag, a digital signature, and a 3-bit message type.
-----------------------------------------------------------------------------
F H1 H2 H3 H4 H5 H6 H7 H8 H9 R6 R7 R8 R9 U Q D M Type
c28 c28 c28 c28 c28 c28 c28 c28 c28 c28 r5 r5 r5 r5 u5 q1 d20 i3=0 Std Msg
280 300 305 326 329
=============================================================================
i3 = 1: If Fox uses a compound callsign we have space for only 8 Hound calls.
Otherwise like type i3=0.
-----------------------------------------------------------------------------
FC H1 H2 H2 H4 H5 H6 H7 H8 R5 R6 R7 R8 U Q D M
c58 c28 c28 c28 c28 c28 c28 c28 c28 r5 r5 r5 r5 u3 q1 d20 i3=1
58 282 302 305 326 329
=============================================================================
i3 = 2: A free text message with up to 26 characters can be transmitted along
with messages to as many as 4 Hounds conveying either reports or RR73s.
-----------------------------------------------------------------------------
F H1 H2 H3 H4 R1 R2 R3 R4 T T U Q D M Type
c28 c28 c28 c28 c28 r5 r5 r5 r5 t71 t71 u3 q1 d20 i3=2 FT+4H
140 160 302 305 326 329
=============================================================================
i3 = 3: Message "CQ FoxCall Grid <Free text>"
-----------------------------------------------------------------------------
FC G T T U Q D M Type
c58 g15 t71 t71 u90 q1 d20 i3=3 CQ FT
58 73 144 215 305 326 329
=============================================================================
D Digital signature (20 bits)
F Fox call (28 bits)
FC Compound Fox call (58 bits)
G Grid locator (15 bits)
H Hound call (28 bits)
M Message type (3 bits)
Q MoreCQs flag
R Report, (5 bits: -18 to +12 dB, or RR73)
T Free text, up to 26 characters total
U Unused bits
Unused callsign slots are set to the numerical value for "QU1RKS", and
ignored when received. Similarly for unused t71 slots. Unused report
slots are set to 0 (-20 dB). "CQ FoxCall" will be displayed along
with other messages if the "q1" bit is 1.
The SuperFox decoder displays its results with a separate line for each Hound.
Thus, the old-style message "K1ABC RR73; W9XYZ <VP8PJ> -14" becomes
K1ABC VP8PJ RR73
W9XYZ VP8PJ -14

View File

@ -1,19 +0,0 @@
subroutine twkfreq2(c3,c4,npts,fsample,fshift)
! Adjust frequency of complex waveform
complex c3(npts)
complex c4(npts)
complex w,wstep
data twopi/6.283185307/
w=1.0
dphi=fshift*twopi/fsample
wstep=cmplx(cos(dphi),sin(dphi))
do i=1,npts
w=w*wstep
c4(i)=w*c3(i)
enddo
return
end subroutine twkfreq2

View File

@ -9,6 +9,7 @@
#include "pimpl_h.hpp"
class Configuration;
class QDateTime;
class QSqlTableModel;
class QTextStream;
class AD1CCty;

View File

@ -1,109 +0,0 @@
#include "otpgenerator.h"
#include <QMessageAuthenticationCode>
#include <QtEndian>
#include <QDateTime>
#include <QtMath>
// FROM https://github.com/RikudouSage/QtOneTimePassword/
/*
MIT License
Copyright (c) 2023 Dominik Chrástecký
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
OTPGenerator::OTPGenerator(QObject *parent)
: QObject{parent}
{
}
QByteArray OTPGenerator::generateHOTP(const QByteArray &rawSecret, quint64 counter, int length)
{
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
counter = qToBigEndian(counter);
#endif
QByteArray data;
data.reserve(8);
for (int i = 7; i >= 0; --i) {
data.append(counter & 0xff);
counter >>= 8;
}
QMessageAuthenticationCode mac(QCryptographicHash::Sha1);
mac.setKey(rawSecret);
mac.addData(data);
QByteArray hmac = mac.result();
int offset = hmac.at(hmac.length() - 1) & 0xf;
quint32 truncatedHash = ((hmac.at(offset) & 0x7f) << 24)
| ((hmac.at(offset + 1) & 0xff) << 16)
| ((hmac.at(offset + 2) & 0xff) << 8)
| (hmac.at(offset + 3) & 0xff);
int modulus = int(qPow(10, length));
return QByteArray::number(truncatedHash % modulus, 10).rightJustified(length, '0');
}
QString OTPGenerator::generateHOTP(const QString &secret, quint64 counter, int length)
{
return generateHOTP(fromBase32(secret), counter, length);
}
QByteArray OTPGenerator::generateTOTP(const QByteArray &rawSecret, int length)
{
const qint64 counter = QDateTime::currentDateTime().toMSecsSinceEpoch() / 30000;
return generateHOTP(rawSecret, counter, length);
}
QString OTPGenerator::generateTOTP(const QString &secret, int length)
{
return generateTOTP(fromBase32(secret), length);
}
QString OTPGenerator::generateTOTP(const QString &secret, QDateTime dt, int length)
{
const qint64 counter = dt.toMSecsSinceEpoch() / 30000;
return generateHOTP(fromBase32(secret), counter, length);
}
QByteArray OTPGenerator::fromBase32(const QString &input)
{
QByteArray result;
result.reserve((input.length() * 5 + 7) / 8);
int buffer = 0;
int bitsLeft = 0;
for (int i = 0; i < input.length(); i++) {
int ch = input[i].toLatin1();
int value;
if (ch >= 'A' && ch <= 'Z')
value = ch - 'A';
else if (ch >= '2' && ch <= '7')
value = 26 + ch - '2';
else
continue;
buffer = (buffer << 5) | value;
bitsLeft += 5;
if (bitsLeft >= 8) {
result.append(buffer >> (bitsLeft - 8));
bitsLeft -= 8;
}
}
return result;
}

View File

@ -1,50 +0,0 @@
#ifndef OTPGENERATOR_H
#define OTPGENERATOR_H
/*
MIT License
Copyright (c) 2023 Dominik Chrástecký
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include <QObject>
#define BASE32_CHARSET "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
class OTPGenerator : public QObject
{
Q_OBJECT
public:
explicit OTPGenerator(QObject *parent = nullptr);
QByteArray generateHOTP(const QByteArray &rawSecret, quint64 counter, int length);
Q_INVOKABLE QString generateHOTP(const QString &secret, quint64 counter, int length);
QByteArray generateTOTP(const QByteArray &rawSecret, int length);
Q_INVOKABLE QString generateTOTP(const QString &secret, QDateTime dt, int length);
Q_INVOKABLE QString generateTOTP(const QString &secret, int length);
private:
QByteArray fromBase32(const QString &input);
signals:
};
#endif // OTPGENERATOR_H

View File

@ -1,7 +1,7 @@
subroutine decode0(dd,ss,savg)
use timer_module, only: timer
parameter (NSMAX=60*96000,NFFT=32768)
parameter (NSMAX=60*96000)
real*4 dd(2,NSMAX),ss(400,NFFT),savg(NFFT)
real*8 fcenter

View File

@ -89,7 +89,7 @@
</message>
<message>
<location filename="../widgets/activeStations.ui" line="141"/>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check this box to show only stations ready to be called.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<source>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check tis box to show only stations ready to be called.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</source>
<translation>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Seleziona questa casella per visualizzare solo le stazioni pronte per essere chiamate.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</translation>
</message>
<message>

File diff suppressed because it is too large Load Diff

6668
translations/wsjtx_zh_HK.ts Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -40,26 +40,6 @@ void ActiveStations::changeFont (QFont const& font)
updateGeometry ();
}
void ActiveStations::clearStations() {
m_textbuffer.clear();
m_decodes_by_frequency.clear();
}
void ActiveStations::addLine(QString line) {
QString m_textbuffer = "";
// "012700 -1 0.2 210 ~ KJ7COA JA2HGF -14"
unsigned freq = line.mid(16, 4).toUInt();
m_decodes_by_frequency[freq] = line;
// show them in frequency order
QMap<int, QString>::const_iterator i = m_decodes_by_frequency.constBegin();
m_textbuffer.clear();
while (i != m_decodes_by_frequency.constEnd()) {
m_textbuffer.append(i.value());
++i;
}
this->displayRecentStations(m_mode, m_textbuffer);
}
void ActiveStations::read_settings ()
{
SettingsGroup group {settings_, "ActiveStations"};
@ -80,7 +60,8 @@ void ActiveStations::write_settings ()
settings_->setValue("WantedOnly",ui->cbWantedOnly->isChecked());
}
void ActiveStations::setupUi(QString mode) {
void ActiveStations::displayRecentStations(QString mode, QString const& t)
{
if(mode!=m_mode) {
m_mode=mode;
ui->cbReadyOnly->setText(" Ready only");
@ -90,37 +71,24 @@ void ActiveStations::setupUi(QString mode) {
ui->cbReadyOnly->setText("* CQ only");
} else if(m_mode=="Q65-pileup") {
ui->header_label2->setText(" N Freq Call Grid El Age(h)");
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "Wanted only", nullptr));
} else if(m_mode=="Fox Mode" || m_mode=="SuperFox Mode" ) {
ui->header_label2->setText(" UTC dB DT Freq " + tr("Message"));
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "My call only", nullptr));
this->setClickOK(true);
} else {
ui->header_label2->setText(" N Call Grid Az S/N Freq Tx Age Pts");
ui->label->setText("Rate:");
ui->cbWantedOnly->setText(QCoreApplication::translate("ActiveStations", "Wanted only", nullptr));
}
bool b=(m_mode.left(3)=="Q65");
bool is_fox_mode =(m_mode=="Fox Mode");
ui->bandChanges->setVisible(!b && !is_fox_mode);
ui->cbReadyOnly->setVisible(m_mode != "Q65-pileup" && !is_fox_mode);
ui->cbWantedOnly->setVisible(m_mode != "Q65-pileup"); // this is used for "My call only" in Fox mode
ui->label_2->setVisible(!b && !is_fox_mode);
ui->label_3->setVisible(!b && !is_fox_mode);
ui->score->setVisible(!b && !is_fox_mode);
ui->sbMaxRecent->setVisible(!b && !is_fox_mode);
ui->bandChanges->setVisible(!b);
ui->cbReadyOnly->setVisible(m_mode!="Q65-pileup");
ui->cbWantedOnly->setVisible(m_mode!="Q65-pileup");
ui->label_2->setVisible(!b);
ui->label_3->setVisible(!b);
ui->score->setVisible(!b);
ui->sbMaxRecent->setVisible(!b);
b=(m_mode!="Q65-pileup" && !is_fox_mode);
b=(m_mode!="Q65-pileup");
ui->sbMaxAge->setVisible(b);
ui->label->setVisible(b);
ui->rate->setVisible(b);
}
}
void ActiveStations::displayRecentStations(QString mode, QString const& t)
{
setupUi(mode);
bool bClickOK=m_clickOK;
m_clickOK=false;
ui->RecentStationsPlainTextEdit->setPlainText(t);
@ -175,10 +143,7 @@ void ActiveStations::on_textEdit_clicked()
if(text!="") {
int nline=text.left(2).toInt();
if(QGuiApplication::keyboardModifiers().testFlag(Qt::ControlModifier)) nline=-nline;
if (!m_mode.contains("fox", Qt::CaseInsensitive))
emit callSandP(nline);
else
emit queueActiveWindowHound(text);
}
}
}

View File

@ -3,7 +3,6 @@
#define ARRL_DIGI_H_
#include <QWidget>
#include <QMap>
class QSettings;
class QFont;
@ -21,7 +20,6 @@ public:
explicit ActiveStations(QSettings *, QFont const&, QWidget * parent = 0);
~ActiveStations();
void displayRecentStations(QString mode, QString const&);
void setupUi(QString display_mode);
void changeFont (QFont const&);
int maxRecent();
int maxAge();
@ -32,8 +30,6 @@ public:
void setRate(int n);
void setBandChanges(int n);
void setScore(int n);
void clearStations();
void addLine(QString);
bool m_clickOK=false;
bool m_bReadyOnly;
@ -45,16 +41,14 @@ private:
Q_SIGNAL void callSandP(int nline);
Q_SIGNAL void activeStationsDisplay();
Q_SIGNAL void cursorPositionChanged();
Q_SIGNAL void queueActiveWindowHound(QString text);
Q_SLOT void on_cbReadyOnly_toggled(bool b);
Q_SLOT void on_cbWantedOnly_toggled(bool b);
Q_SLOT void on_textEdit_clicked();
// qint64 m_msec0=0;
QString m_mode="";
QSettings * settings_;
QString m_textbuffer=""; // F/H mode band decodes
QMap<int, QString> m_decodes_by_frequency; // store decodes for F/H band awareness by frequency
QScopedPointer<Ui::ActiveStations> ui;
};

View File

@ -69,7 +69,7 @@
<item row="0" column="3">
<widget class="QCheckBox" name="cbReadyOnly">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check this box to show only stations ready to be called.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Check tis box to show only stations ready to be called.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Ready only</string>

View File

@ -213,11 +213,27 @@ void DisplayText::insertText(QString const& text, QColor bg, QColor fg
void DisplayText::extend_vertical_scrollbar (int min, int max)
{
static int mod_last;
static int height;
if (high_volume_ && m_config && m_config->decodes_from_top ())
{
auto m = modified_vertical_scrollbar_max_;
if (m != mod_last) { height = m - mod_last;mod_last = m; }
//auto vp_margins2 = viewportMargins ();
if (height == 0 && m > viewport()->height()) height = abs( - viewport()->height());
//LOG_INFO ("scrollbar min=" << min << " max=" << max << " mod=" << modified_vertical_scrollbar_max_ << " height=" << viewport()->height() << " top=" << vp_margins2.top() << " bottom=" << vp_margins2.bottom()) << " height=" << height << " mod_last=" << mod_last;
if (max > 60000)
{
QString tmp = toPlainText();
while (tmp != NULL && tmp.length() > 100 && max > 50000)
{
tmp.remove(0, tmp.indexOf("\n")+1);
max -= height;
}
setPlainText(tmp);
}
if (max && max != modified_vertical_scrollbar_max_)
{
setViewportMargins (0,4,0,0); // ensure first line is readable
auto vp_margins = viewportMargins ();
// add enough to vertical scroll bar range to allow last
// decode to just scroll of the top of the view port
@ -230,10 +246,6 @@ void DisplayText::extend_vertical_scrollbar (int min, int max)
void DisplayText::new_period ()
{
if (m_config->decodes_from_top ()) {
document ()->setMaximumBlockCount (4800);
document ()->setMaximumBlockCount (5000);
}
extend_vertical_scrollbar (verticalScrollBar ()->minimum (), verticalScrollBar ()->maximum ());
if (high_volume_ && m_config && m_config->decodes_from_top () && !vertical_scroll_connection_)
{
@ -506,11 +518,11 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
bool bFastMode, double TRperiod,bool bSuperfox)
bool bFastMode, double TRperiod)
{
QString t1=" @ ";
if(modeTx=="FT4") t1=" + ";
if(modeTx.contains("FT8")) t1=" ~ ";
if(modeTx=="FT8") t1=" ~ ";
if(modeTx=="JT4") t1=" $ ";
if(modeTx=="Q65") t1=" : ";
if(modeTx=="JT65") t1=" # ";
@ -534,18 +546,7 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx
QColor fg;
highlight_types types {Highlight::Tx};
set_colours (m_config, &bg, &fg, types);
if(bSuperfox and t.contains(";")) {
int i0=t.indexOf(";");
int i1=t.indexOf("<");
int i2=t.indexOf(">");
QString foxcall=t.mid(i1+1,i2-i1-1);
t2=t.left(i0).replace(" RR73", " " + foxcall + " RR73");
QString t3=t.left(24) + t.mid(i0+2,-1).remove("<").remove(">");
insertText (t2, bg, fg);
insertText (t3, bg, fg);
} else {
insertText (t, bg, fg);
}
}
void DisplayText::displayQSY(QString text)
@ -560,22 +561,6 @@ void DisplayText::displayHoundToBeCalled(QString t, bool bAtTop, QColor bg, QCol
insertText(t, bg, fg, "", "", bAtTop ? QTextCursor::Start : QTextCursor::End);
}
void DisplayText::setHighlightedHoundText(QString t) {
QColor bg=QColor{255,255,255};
QColor fg=QColor{0,0,0};
highlight_types types{Highlight::Call};
set_colours(m_config, &bg, &fg, types);
// t is multiple lines of text, each line is a hound calling
// iterate through each line and highlight the callsign
auto lines = t.split(QChar('\n'), SkipEmptyParts);
clear();
foreach (auto line, lines)
{
auto fields = line.split(QChar(' '), SkipEmptyParts);
insertText(line, bg, fg, fields.first(), QString{});
}
}
namespace
{
void update_selection (QTextCursor& cursor, QColor const& bg, QColor const& fg)
@ -635,11 +620,6 @@ void DisplayText::highlight_callsign (QString const& callsign, QColor const& bg,
{
return;
}
if (callsign == "CLEARALL!") // programmatic means of clearing all highlighting
{
highlighted_calls_.clear();
return;
}
auto regexp = callsign;
// allow for hashed callsigns and escape any regexp metacharacters
QRegularExpression target {QString {"<?"}

View File

@ -30,13 +30,10 @@ public:
void displayDecodedText(DecodedText const& decodedText, QString const& myCall, QString const& mode,
bool displayDXCCEntity, LogBook const& logBook,
QString const& currentBand=QString {}, bool ppfx=false, bool bCQonly=false,
bool haveFSpread = false, float fSpread = 0.0, bool bDisplayPoints=false,
int points=-99);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode,
double TRperiod, bool bSuperfox);
bool haveFSpread = false, float fSpread = 0.0, bool bDisplayPoints=false, int points=-99);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode, double TRperiod);
void displayQSY(QString text);
void displayHoundToBeCalled(QString t, bool bAtTop=false, QColor bg = QColor {}, QColor fg = QColor {});
void setHighlightedHoundText(QString text);
void new_period ();
QString CQPriority(){return m_CQPriority;};
qint32 m_points;

View File

@ -167,7 +167,7 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
auto special_op = m_config->special_op_id ();
if (SpOp::FOX == special_op
|| (m_config->autoLog ()
&& ((SpOp::NONE < special_op && special_op < SpOp::FOX) || SpOp::ARRL_DIGI == special_op)))
&& SpOp::NONE < special_op && special_op < SpOp::FOX))
{
// allow auto logging in Fox mode and contests
accept();

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More