Compare commits
129 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4df65585a3 | |||
| f406553a5f | |||
| ecf14dcb5c | |||
| 5163a4a630 | |||
| 4af1a14961 | |||
| 842896d867 | |||
| 4406e99670 | |||
| 79785dbef5 | |||
| 1d1bc254a4 | |||
| 4ddccd99a1 | |||
| dd6f50a5a3 | |||
| 55c365b834 | |||
| b55f8ba5c5 | |||
| fd77e5440f | |||
| 19cb0b859d | |||
| 3d3be02830 | |||
| 55f04d3cd7 | |||
| 693eec8b4b | |||
| 9244ac08c6 | |||
| 8004c51ed2 | |||
| 52b67a5609 | |||
| 3e7c64e994 | |||
| d9d3e6fba3 | |||
| 09cea086c7 | |||
| a013e79eff | |||
| a3e004375e | |||
| f018a622ce | |||
| 565c031b28 | |||
| d88d8aa440 | |||
| 3a59599253 | |||
| 22e4b0891e | |||
| 8c564b6637 | |||
| 97763ed82d | |||
| a7849c5b72 | |||
| 04394273dd | |||
| 1052dd3f9f | |||
| 78ed799a8b | |||
| c0d08f87b6 | |||
| f92b3db5ea | |||
| cebed44ccd | |||
| d47d88681b | |||
| 1be0ee4f4f | |||
| 43d8986e0a | |||
| fd69dce0ae | |||
| b2fb3f31ac | |||
| db704858e2 | |||
| 1d11f0f8ba | |||
| b6bc50a8e1 | |||
| 5addf8f61f | |||
| 367966f5e6 | |||
| caaaa957b6 | |||
| c440d4c143 | |||
| 740c0b4c04 | |||
| f5ce9f0e30 | |||
| 0a6ec136f9 | |||
| d5e1f2822d | |||
| 3fffb45338 | |||
| 1d255b1ebf | |||
| bb97799bdf | |||
| cc6a719f6d | |||
| ccd380356a | |||
| 9f8583c8e2 | |||
| c9016d7378 | |||
| cd683f9bf7 | |||
| 6d7b187269 | |||
| 13308a38f8 | |||
| 804605e9e6 | |||
| 4e981da9c8 | |||
| 6436e163bd | |||
| 379a0fa78f | |||
| 1c4a2ab7d8 | |||
| 54f6bdb0af | |||
| 5a0e2a8b14 | |||
| 1a9c611195 | |||
| c70661461e | |||
| 1f866e14f1 | |||
| c0e8a791e6 | |||
| 74523985bb | |||
| 8d28ea345a | |||
| 33446297fa | |||
| 6f648d5a60 | |||
| f1f618bbcd | |||
| ac7da998a2 | |||
| b3cd705fb6 | |||
| 604e366d4a | |||
| 8d73805dce | |||
| 5c491dc10d | |||
| d611259a25 | |||
| 00f2d46167 | |||
| e4cba50144 | |||
| 440311a75b | |||
| 38fc98702b | |||
| 6201de8c12 | |||
| 4321bd5e75 | |||
| 9f7fd2e7e2 | |||
| 65a2411c46 | |||
| d076eedeb8 | |||
| 7da30200f5 | |||
| cac5f798a3 | |||
| 41fb7481ed | |||
| 09effda8e4 | |||
| eecf7f65c7 | |||
| 0618b1cc09 | |||
| 00685b9117 | |||
| a5a6c95a44 | |||
| 8612f2cd32 | |||
| 5fa60659f3 | |||
| 08629019d4 | |||
| 7293d1e796 | |||
| aff001ce96 | |||
| 31d80a9b1d | |||
| 9010fa07c0 | |||
| 121bb0fdb5 | |||
| 47a7c06854 | |||
| c4089c0af9 | |||
| 5c28d154ff | |||
| 6dfd037736 | |||
| 3767b347d9 | |||
| ff12fd2240 | |||
| 6a0fea1d0a | |||
| f11e02c966 | |||
| 0763ecfe37 | |||
| 4c3ed5c719 | |||
| 0064176736 | |||
| 67386a09c7 | |||
| 3c81108cc6 | |||
| 71ed0c1f10 | |||
| 20a44171e4 | |||
| 644633721f |
+136
-23
@@ -454,6 +454,7 @@ private:
|
|||||||
Q_SLOT void on_delete_macro_push_button_clicked (bool = false);
|
Q_SLOT void on_delete_macro_push_button_clicked (bool = false);
|
||||||
Q_SLOT void on_PTT_method_button_group_buttonClicked (int);
|
Q_SLOT void on_PTT_method_button_group_buttonClicked (int);
|
||||||
Q_SLOT void on_station_message_line_edit_textChanged(QString const&);
|
Q_SLOT void on_station_message_line_edit_textChanged(QString const&);
|
||||||
|
Q_SLOT void on_groups_line_edit_textChanged(QString const&);
|
||||||
Q_SLOT void on_qth_message_line_edit_textChanged(QString const&);
|
Q_SLOT void on_qth_message_line_edit_textChanged(QString const&);
|
||||||
Q_SLOT void on_cq_message_line_edit_textChanged(QString const&);
|
Q_SLOT void on_cq_message_line_edit_textChanged(QString const&);
|
||||||
Q_SLOT void on_reply_message_line_edit_textChanged(QString const&);
|
Q_SLOT void on_reply_message_line_edit_textChanged(QString const&);
|
||||||
@@ -462,6 +463,9 @@ private:
|
|||||||
void delete_selected_macros (QModelIndexList);
|
void delete_selected_macros (QModelIndexList);
|
||||||
Q_SLOT void on_save_path_select_push_button_clicked (bool);
|
Q_SLOT void on_save_path_select_push_button_clicked (bool);
|
||||||
Q_SLOT void on_azel_path_select_push_button_clicked (bool);
|
Q_SLOT void on_azel_path_select_push_button_clicked (bool);
|
||||||
|
Q_SLOT void on_sound_cq_path_select_push_button_clicked();
|
||||||
|
Q_SLOT void on_sound_cq_path_test_push_button_clicked();
|
||||||
|
Q_SLOT void on_sound_cq_path_reset_push_button_clicked();
|
||||||
Q_SLOT void on_sound_dm_path_select_push_button_clicked();
|
Q_SLOT void on_sound_dm_path_select_push_button_clicked();
|
||||||
Q_SLOT void on_sound_dm_path_test_push_button_clicked();
|
Q_SLOT void on_sound_dm_path_test_push_button_clicked();
|
||||||
Q_SLOT void on_sound_dm_path_reset_push_button_clicked();
|
Q_SLOT void on_sound_dm_path_reset_push_button_clicked();
|
||||||
@@ -516,6 +520,7 @@ private:
|
|||||||
QDir default_azel_directory_;
|
QDir default_azel_directory_;
|
||||||
QDir azel_directory_;
|
QDir azel_directory_;
|
||||||
|
|
||||||
|
QString sound_cq_path_; // cq message sound file
|
||||||
QString sound_dm_path_; // directed message sound file
|
QString sound_dm_path_; // directed message sound file
|
||||||
QString sound_am_path_; // alert message sound file
|
QString sound_am_path_; // alert message sound file
|
||||||
|
|
||||||
@@ -584,6 +589,7 @@ private:
|
|||||||
QString my_callsign_;
|
QString my_callsign_;
|
||||||
QString my_grid_;
|
QString my_grid_;
|
||||||
QString my_station_;
|
QString my_station_;
|
||||||
|
QStringList my_groups_;
|
||||||
QString my_qth_;
|
QString my_qth_;
|
||||||
QString cq_;
|
QString cq_;
|
||||||
QString reply_;
|
QString reply_;
|
||||||
@@ -626,7 +632,7 @@ private:
|
|||||||
bool spot_to_reporting_networks_;
|
bool spot_to_reporting_networks_;
|
||||||
bool transmit_directed_;
|
bool transmit_directed_;
|
||||||
bool autoreply_off_at_startup_;
|
bool autoreply_off_at_startup_;
|
||||||
bool beacon_anywhere_;
|
bool heartbeat_anywhere_;
|
||||||
bool relay_disabled_;
|
bool relay_disabled_;
|
||||||
bool monitor_off_at_startup_;
|
bool monitor_off_at_startup_;
|
||||||
bool monitor_last_used_;
|
bool monitor_last_used_;
|
||||||
@@ -636,11 +642,11 @@ private:
|
|||||||
bool insert_blank_;
|
bool insert_blank_;
|
||||||
bool DXCC_;
|
bool DXCC_;
|
||||||
bool ppfx_;
|
bool ppfx_;
|
||||||
bool clear_DX_;
|
bool clear_callsign_;
|
||||||
bool miles_;
|
bool miles_;
|
||||||
bool quick_call_;
|
bool quick_call_;
|
||||||
bool disable_TX_on_73_;
|
bool disable_TX_on_73_;
|
||||||
int beacon_;
|
int heartbeat_;
|
||||||
int watchdog_;
|
int watchdog_;
|
||||||
bool TX_messages_;
|
bool TX_messages_;
|
||||||
bool enable_VHF_features_;
|
bool enable_VHF_features_;
|
||||||
@@ -757,7 +763,7 @@ void Configuration::set_spot_to_reporting_networks (bool spot)
|
|||||||
|
|
||||||
bool Configuration::transmit_directed() const { return m_->transmit_directed_; }
|
bool Configuration::transmit_directed() const { return m_->transmit_directed_; }
|
||||||
bool Configuration::autoreply_off_at_startup () const {return m_->autoreply_off_at_startup_;}
|
bool Configuration::autoreply_off_at_startup () const {return m_->autoreply_off_at_startup_;}
|
||||||
bool Configuration::beacon_anywhere() const { return m_->beacon_anywhere_;}
|
bool Configuration::heartbeat_anywhere() const { return m_->heartbeat_anywhere_;}
|
||||||
bool Configuration::relay_off() const { return m_->relay_disabled_; }
|
bool Configuration::relay_off() const { return m_->relay_disabled_; }
|
||||||
bool Configuration::monitor_off_at_startup () const {return m_->monitor_off_at_startup_;}
|
bool Configuration::monitor_off_at_startup () const {return m_->monitor_off_at_startup_;}
|
||||||
bool Configuration::monitor_last_used () const {return m_->rig_is_dummy_ || m_->monitor_last_used_;}
|
bool Configuration::monitor_last_used () const {return m_->rig_is_dummy_ || m_->monitor_last_used_;}
|
||||||
@@ -767,11 +773,11 @@ bool Configuration::prompt_to_log () const {return m_->prompt_to_log_;}
|
|||||||
bool Configuration::insert_blank () const {return m_->insert_blank_;}
|
bool Configuration::insert_blank () const {return m_->insert_blank_;}
|
||||||
bool Configuration::DXCC () const {return m_->DXCC_;}
|
bool Configuration::DXCC () const {return m_->DXCC_;}
|
||||||
bool Configuration::ppfx() const {return m_->ppfx_;}
|
bool Configuration::ppfx() const {return m_->ppfx_;}
|
||||||
bool Configuration::clear_DX () const {return m_->clear_DX_;}
|
bool Configuration::clear_callsign () const {return m_->clear_callsign_;}
|
||||||
bool Configuration::miles () const {return m_->miles_;}
|
bool Configuration::miles () const {return m_->miles_;}
|
||||||
bool Configuration::quick_call () const {return m_->quick_call_;}
|
bool Configuration::quick_call () const {return m_->quick_call_;}
|
||||||
bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;}
|
bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;}
|
||||||
int Configuration::beacon () const {return m_->beacon_;}
|
int Configuration::heartbeat () const {return m_->heartbeat_;}
|
||||||
int Configuration::watchdog () const {return m_->watchdog_;}
|
int Configuration::watchdog () const {return m_->watchdog_;}
|
||||||
bool Configuration::TX_messages () const {return m_->TX_messages_;}
|
bool Configuration::TX_messages () const {return m_->TX_messages_;}
|
||||||
bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features_;}
|
bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features_;}
|
||||||
@@ -808,6 +814,7 @@ QStringListModel * Configuration::macros () {return &m_->macros_;}
|
|||||||
QStringListModel const * Configuration::macros () const {return &m_->macros_;}
|
QStringListModel const * Configuration::macros () const {return &m_->macros_;}
|
||||||
QDir Configuration::save_directory () const {return m_->save_directory_;}
|
QDir Configuration::save_directory () const {return m_->save_directory_;}
|
||||||
QDir Configuration::azel_directory () const {return m_->azel_directory_;}
|
QDir Configuration::azel_directory () const {return m_->azel_directory_;}
|
||||||
|
QString Configuration::sound_cq_path() const {return m_->sound_cq_path_;}
|
||||||
QString Configuration::sound_dm_path() const {return m_->sound_dm_path_;}
|
QString Configuration::sound_dm_path() const {return m_->sound_dm_path_;}
|
||||||
QString Configuration::sound_am_path() const {return m_->sound_am_path_;}
|
QString Configuration::sound_am_path() const {return m_->sound_am_path_;}
|
||||||
QString Configuration::rig_name () const {return m_->rig_params_.rig_name;}
|
QString Configuration::rig_name () const {return m_->rig_params_.rig_name;}
|
||||||
@@ -934,6 +941,24 @@ QString Configuration::my_station() const
|
|||||||
return station.trimmed();
|
return station.trimmed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QSet<QString> Configuration::my_groups() const {
|
||||||
|
return QSet<QString>::fromList(m_->my_groups_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Configuration::addGroup(QString const &group){
|
||||||
|
QSet<QString> groups = my_groups();
|
||||||
|
groups.insert(group.trimmed());
|
||||||
|
m_->my_groups_ = groups.toList();
|
||||||
|
m_->write_settings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Configuration::removeGroup(QString const &group){
|
||||||
|
QSet<QString> groups = my_groups();
|
||||||
|
groups.remove(group.trimmed());
|
||||||
|
m_->my_groups_ = groups.toList();
|
||||||
|
m_->write_settings();
|
||||||
|
}
|
||||||
|
|
||||||
QString Configuration::my_qth() const
|
QString Configuration::my_qth() const
|
||||||
{
|
{
|
||||||
return m_->my_qth_.trimmed();
|
return m_->my_qth_.trimmed();
|
||||||
@@ -1036,6 +1061,7 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
|
|||||||
, default_audio_output_device_selected_ {false}
|
, default_audio_output_device_selected_ {false}
|
||||||
{
|
{
|
||||||
ui_->setupUi (this);
|
ui_->setupUi (this);
|
||||||
|
|
||||||
// ui_->groupBox_6->setVisible(false); //### Temporary ??? ###
|
// ui_->groupBox_6->setVisible(false); //### Temporary ??? ###
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1300,6 +1326,7 @@ void Configuration::impl::initialize_models ()
|
|||||||
ui_->callsign_aging_spin_box->setValue(callsign_aging_);
|
ui_->callsign_aging_spin_box->setValue(callsign_aging_);
|
||||||
ui_->activity_aging_spin_box->setValue(activity_aging_);
|
ui_->activity_aging_spin_box->setValue(activity_aging_);
|
||||||
ui_->station_message_line_edit->setText (my_station_.toUpper());
|
ui_->station_message_line_edit->setText (my_station_.toUpper());
|
||||||
|
ui_->groups_line_edit->setText(my_groups_.join(", "));
|
||||||
ui_->qth_message_line_edit->setText (my_qth_.toUpper());
|
ui_->qth_message_line_edit->setText (my_qth_.toUpper());
|
||||||
ui_->cq_message_line_edit->setText(cq_.toUpper());
|
ui_->cq_message_line_edit->setText(cq_.toUpper());
|
||||||
ui_->reply_message_line_edit->setText (reply_.toUpper());
|
ui_->reply_message_line_edit->setText (reply_.toUpper());
|
||||||
@@ -1324,6 +1351,7 @@ void Configuration::impl::initialize_models ()
|
|||||||
ui_->PTT_method_button_group->button (rig_params_.ptt_type)->setChecked (true);
|
ui_->PTT_method_button_group->button (rig_params_.ptt_type)->setChecked (true);
|
||||||
ui_->save_path_display_label->setText (save_directory_.absolutePath ());
|
ui_->save_path_display_label->setText (save_directory_.absolutePath ());
|
||||||
ui_->azel_path_display_label->setText (azel_directory_.absolutePath ());
|
ui_->azel_path_display_label->setText (azel_directory_.absolutePath ());
|
||||||
|
ui_->sound_cq_path_display_label->setText(sound_cq_path_);
|
||||||
ui_->sound_dm_path_display_label->setText(sound_dm_path_);
|
ui_->sound_dm_path_display_label->setText(sound_dm_path_);
|
||||||
ui_->sound_am_path_display_label->setText(sound_am_path_);
|
ui_->sound_am_path_display_label->setText(sound_am_path_);
|
||||||
ui_->CW_id_after_73_check_box->setChecked (id_after_73_);
|
ui_->CW_id_after_73_check_box->setChecked (id_after_73_);
|
||||||
@@ -1331,7 +1359,7 @@ void Configuration::impl::initialize_models ()
|
|||||||
ui_->psk_reporter_check_box->setChecked (spot_to_reporting_networks_);
|
ui_->psk_reporter_check_box->setChecked (spot_to_reporting_networks_);
|
||||||
ui_->transmit_directed_check_box->setChecked(transmit_directed_);
|
ui_->transmit_directed_check_box->setChecked(transmit_directed_);
|
||||||
ui_->autoreply_off_check_box->setChecked (autoreply_off_at_startup_);
|
ui_->autoreply_off_check_box->setChecked (autoreply_off_at_startup_);
|
||||||
ui_->beacon_anywhere_check_box->setChecked(beacon_anywhere_);
|
ui_->heartbeat_anywhere_check_box->setChecked(heartbeat_anywhere_);
|
||||||
ui_->relay_disabled_check_box->setChecked(relay_disabled_);
|
ui_->relay_disabled_check_box->setChecked(relay_disabled_);
|
||||||
ui_->monitor_off_check_box->setChecked (monitor_off_at_startup_);
|
ui_->monitor_off_check_box->setChecked (monitor_off_at_startup_);
|
||||||
ui_->monitor_last_used_check_box->setChecked (monitor_last_used_);
|
ui_->monitor_last_used_check_box->setChecked (monitor_last_used_);
|
||||||
@@ -1339,11 +1367,11 @@ void Configuration::impl::initialize_models ()
|
|||||||
ui_->stations_table_view->setEnabled(ui_->auto_switch_bands_check_box->isChecked());
|
ui_->stations_table_view->setEnabled(ui_->auto_switch_bands_check_box->isChecked());
|
||||||
ui_->report_in_comments_check_box->setChecked (report_in_comments_);
|
ui_->report_in_comments_check_box->setChecked (report_in_comments_);
|
||||||
ui_->prompt_to_log_check_box->setChecked (prompt_to_log_);
|
ui_->prompt_to_log_check_box->setChecked (prompt_to_log_);
|
||||||
ui_->clear_DX_check_box->setChecked (clear_DX_);
|
ui_->clear_callsign_check_box->setChecked (clear_callsign_);
|
||||||
ui_->miles_check_box->setChecked (miles_);
|
ui_->miles_check_box->setChecked (miles_);
|
||||||
ui_->quick_call_check_box->setChecked (quick_call_);
|
ui_->quick_call_check_box->setChecked (quick_call_);
|
||||||
ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_);
|
ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_);
|
||||||
ui_->beacon_spin_box->setValue (beacon_);
|
ui_->heartbeat_spin_box->setValue (heartbeat_);
|
||||||
ui_->tx_watchdog_spin_box->setValue (watchdog_);
|
ui_->tx_watchdog_spin_box->setValue (watchdog_);
|
||||||
ui_->enable_VHF_features_check_box->setChecked(enable_VHF_features_);
|
ui_->enable_VHF_features_check_box->setChecked(enable_VHF_features_);
|
||||||
ui_->decode_at_52s_check_box->setChecked(decode_at_52s_);
|
ui_->decode_at_52s_check_box->setChecked(decode_at_52s_);
|
||||||
@@ -1423,7 +1451,7 @@ void Configuration::impl::done (int r)
|
|||||||
{
|
{
|
||||||
// do this here since window is still on screen at this point
|
// do this here since window is still on screen at this point
|
||||||
SettingsGroup g {settings_, "Configuration"};
|
SettingsGroup g {settings_, "Configuration"};
|
||||||
settings_->setValue ("window/geometry", saveGeometry ());
|
settings_->setValue ("WindowGeometry", saveGeometry ());
|
||||||
|
|
||||||
QDialog::done (r);
|
QDialog::done (r);
|
||||||
}
|
}
|
||||||
@@ -1431,16 +1459,19 @@ void Configuration::impl::done (int r)
|
|||||||
void Configuration::impl::read_settings ()
|
void Configuration::impl::read_settings ()
|
||||||
{
|
{
|
||||||
SettingsGroup g {settings_, "Configuration"};
|
SettingsGroup g {settings_, "Configuration"};
|
||||||
restoreGeometry (settings_->value ("window/geometry").toByteArray ());
|
setMinimumSize(800, 400);
|
||||||
|
restoreGeometry (settings_->value ("WindowGeometry").toByteArray ());
|
||||||
|
setMinimumSize(800, 400);
|
||||||
|
|
||||||
auto_switch_bands_ = settings_->value("AutoSwitchBands", false).toBool();
|
auto_switch_bands_ = settings_->value("AutoSwitchBands", false).toBool();
|
||||||
my_callsign_ = settings_->value ("MyCall", QString {}).toString ();
|
my_callsign_ = settings_->value ("MyCall", QString {}).toString ();
|
||||||
my_grid_ = settings_->value ("MyGrid", QString {}).toString ();
|
my_grid_ = settings_->value ("MyGrid", QString {}).toString ();
|
||||||
my_station_ = settings_->value("MyStation", QString {}).toString();
|
my_station_ = settings_->value("MyStation", QString {}).toString();
|
||||||
|
my_groups_ = settings_->value("MyGroups", QStringList{}).toStringList();
|
||||||
callsign_aging_ = settings_->value ("CallsignAging", 0).toInt ();
|
callsign_aging_ = settings_->value ("CallsignAging", 0).toInt ();
|
||||||
activity_aging_ = settings_->value ("ActivityAging", 2).toInt ();
|
activity_aging_ = settings_->value ("ActivityAging", 2).toInt ();
|
||||||
my_qth_ = settings_->value("MyQTH", QString {}).toString();
|
my_qth_ = settings_->value("MyQTH", QString {}).toString();
|
||||||
cq_ = settings_->value("CQMessage", QString {"CQCQCQ"}).toString();
|
cq_ = settings_->value("CQMessage", QString {"CQCQCQ <MYGRID4>"}).toString();
|
||||||
reply_ = settings_->value("Reply", QString {"HW CPY?"}).toString();
|
reply_ = settings_->value("Reply", QString {"HW CPY?"}).toString();
|
||||||
next_color_cq_ = color_cq_ = settings_->value("colorCQ","#66ff66").toString();
|
next_color_cq_ = color_cq_ = settings_->value("colorCQ","#66ff66").toString();
|
||||||
next_color_mycall_ = color_mycall_ = settings_->value("colorMyCall","#ff6666").toString();
|
next_color_mycall_ = color_mycall_ = settings_->value("colorMyCall","#ff6666").toString();
|
||||||
@@ -1525,6 +1556,7 @@ void Configuration::impl::read_settings ()
|
|||||||
RxBandwidth_ = settings_->value ("RxBandwidth", 2500).toInt ();
|
RxBandwidth_ = settings_->value ("RxBandwidth", 2500).toInt ();
|
||||||
save_directory_ = settings_->value ("SaveDir", default_save_directory_.absolutePath ()).toString ();
|
save_directory_ = settings_->value ("SaveDir", default_save_directory_.absolutePath ()).toString ();
|
||||||
azel_directory_ = settings_->value ("AzElDir", default_azel_directory_.absolutePath ()).toString ();
|
azel_directory_ = settings_->value ("AzElDir", default_azel_directory_.absolutePath ()).toString ();
|
||||||
|
sound_cq_path_ = settings_->value ("SoundCQPath", "").toString ();
|
||||||
sound_dm_path_ = settings_->value ("SoundDMPath", "").toString ();
|
sound_dm_path_ = settings_->value ("SoundDMPath", "").toString ();
|
||||||
sound_am_path_ = settings_->value ("SoundAMPath", "").toString ();
|
sound_am_path_ = settings_->value ("SoundAMPath", "").toString ();
|
||||||
|
|
||||||
@@ -1588,7 +1620,7 @@ void Configuration::impl::read_settings ()
|
|||||||
|
|
||||||
transmit_directed_ = settings_->value ("TransmitDirected", true).toBool();
|
transmit_directed_ = settings_->value ("TransmitDirected", true).toBool();
|
||||||
autoreply_off_at_startup_ = settings_->value ("AutoreplyOFF", false).toBool ();
|
autoreply_off_at_startup_ = settings_->value ("AutoreplyOFF", false).toBool ();
|
||||||
beacon_anywhere_ = settings_->value("BeaconAnywhere", false).toBool();
|
heartbeat_anywhere_ = settings_->value("BeaconAnywhere", false).toBool();
|
||||||
relay_disabled_ = settings_->value ("RelayOFF", false).toBool ();
|
relay_disabled_ = settings_->value ("RelayOFF", false).toBool ();
|
||||||
monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool ();
|
monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool ();
|
||||||
monitor_last_used_ = settings_->value ("MonitorLastUsed", false).toBool ();
|
monitor_last_used_ = settings_->value ("MonitorLastUsed", false).toBool ();
|
||||||
@@ -1645,11 +1677,11 @@ void Configuration::impl::read_settings ()
|
|||||||
insert_blank_ = settings_->value ("InsertBlank", false).toBool ();
|
insert_blank_ = settings_->value ("InsertBlank", false).toBool ();
|
||||||
DXCC_ = settings_->value ("DXCCEntity", false).toBool ();
|
DXCC_ = settings_->value ("DXCCEntity", false).toBool ();
|
||||||
ppfx_ = settings_->value ("PrincipalPrefix", false).toBool ();
|
ppfx_ = settings_->value ("PrincipalPrefix", false).toBool ();
|
||||||
clear_DX_ = settings_->value ("ClearCallGrid", false).toBool ();
|
clear_callsign_ = settings_->value ("ClearCallGrid", false).toBool ();
|
||||||
miles_ = settings_->value ("Miles", false).toBool ();
|
miles_ = settings_->value ("Miles", false).toBool ();
|
||||||
quick_call_ = settings_->value ("QuickCall", false).toBool ();
|
quick_call_ = settings_->value ("QuickCall", false).toBool ();
|
||||||
disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool ();
|
disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool ();
|
||||||
beacon_ = settings_->value ("TxBeacon", 30).toInt ();
|
heartbeat_ = settings_->value ("TxBeacon", 30).toInt ();
|
||||||
watchdog_ = settings_->value ("TxIdleWatchdog", 60).toInt ();
|
watchdog_ = settings_->value ("TxIdleWatchdog", 60).toInt ();
|
||||||
if(watchdog_){
|
if(watchdog_){
|
||||||
watchdog_ = qMax(5, watchdog_);
|
watchdog_ = qMax(5, watchdog_);
|
||||||
@@ -1692,6 +1724,7 @@ void Configuration::impl::write_settings ()
|
|||||||
settings_->setValue ("MyCall", my_callsign_);
|
settings_->setValue ("MyCall", my_callsign_);
|
||||||
settings_->setValue ("MyGrid", my_grid_);
|
settings_->setValue ("MyGrid", my_grid_);
|
||||||
settings_->setValue ("MyStation", my_station_);
|
settings_->setValue ("MyStation", my_station_);
|
||||||
|
settings_->setValue ("MyGroups", my_groups_);
|
||||||
settings_->setValue ("MyQTH", my_qth_);
|
settings_->setValue ("MyQTH", my_qth_);
|
||||||
settings_->setValue ("CQMessage", cq_);
|
settings_->setValue ("CQMessage", cq_);
|
||||||
settings_->setValue ("Reply", reply_);
|
settings_->setValue ("Reply", reply_);
|
||||||
@@ -1727,6 +1760,7 @@ void Configuration::impl::write_settings ()
|
|||||||
settings_->setValue ("PTTport", rig_params_.ptt_port);
|
settings_->setValue ("PTTport", rig_params_.ptt_port);
|
||||||
settings_->setValue ("SaveDir", save_directory_.absolutePath ());
|
settings_->setValue ("SaveDir", save_directory_.absolutePath ());
|
||||||
settings_->setValue ("AzElDir", azel_directory_.absolutePath ());
|
settings_->setValue ("AzElDir", azel_directory_.absolutePath ());
|
||||||
|
settings_->setValue ("SoundCQPath", sound_cq_path_);
|
||||||
settings_->setValue ("SoundDMPath", sound_dm_path_);
|
settings_->setValue ("SoundDMPath", sound_dm_path_);
|
||||||
settings_->setValue ("SoundAMPath", sound_am_path_);
|
settings_->setValue ("SoundAMPath", sound_am_path_);
|
||||||
|
|
||||||
@@ -1753,7 +1787,7 @@ void Configuration::impl::write_settings ()
|
|||||||
settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_));
|
settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_));
|
||||||
settings_->setValue ("TransmitDirected", transmit_directed_);
|
settings_->setValue ("TransmitDirected", transmit_directed_);
|
||||||
settings_->setValue ("AutoreplyOFF", autoreply_off_at_startup_);
|
settings_->setValue ("AutoreplyOFF", autoreply_off_at_startup_);
|
||||||
settings_->setValue ("BeaconAnywhere", beacon_anywhere_);
|
settings_->setValue ("BeaconAnywhere", heartbeat_anywhere_);
|
||||||
settings_->setValue ("RelayOFF", relay_disabled_);
|
settings_->setValue ("RelayOFF", relay_disabled_);
|
||||||
settings_->setValue ("MonitorOFF", monitor_off_at_startup_);
|
settings_->setValue ("MonitorOFF", monitor_off_at_startup_);
|
||||||
settings_->setValue ("MonitorLastUsed", monitor_last_used_);
|
settings_->setValue ("MonitorLastUsed", monitor_last_used_);
|
||||||
@@ -1778,11 +1812,11 @@ void Configuration::impl::write_settings ()
|
|||||||
settings_->setValue ("InsertBlank", insert_blank_);
|
settings_->setValue ("InsertBlank", insert_blank_);
|
||||||
settings_->setValue ("DXCCEntity", DXCC_);
|
settings_->setValue ("DXCCEntity", DXCC_);
|
||||||
settings_->setValue ("PrincipalPrefix", ppfx_);
|
settings_->setValue ("PrincipalPrefix", ppfx_);
|
||||||
settings_->setValue ("ClearCallGrid", clear_DX_);
|
settings_->setValue ("ClearCallGrid", clear_callsign_);
|
||||||
settings_->setValue ("Miles", miles_);
|
settings_->setValue ("Miles", miles_);
|
||||||
settings_->setValue ("QuickCall", quick_call_);
|
settings_->setValue ("QuickCall", quick_call_);
|
||||||
settings_->setValue ("73TxDisable", disable_TX_on_73_);
|
settings_->setValue ("73TxDisable", disable_TX_on_73_);
|
||||||
settings_->setValue ("TxBeacon", beacon_);
|
settings_->setValue ("TxBeacon", heartbeat_);
|
||||||
settings_->setValue ("TxIdleWatchdog", watchdog_);
|
settings_->setValue ("TxIdleWatchdog", watchdog_);
|
||||||
settings_->setValue ("Tx2QSO", TX_messages_);
|
settings_->setValue ("Tx2QSO", TX_messages_);
|
||||||
settings_->setValue ("CATForceDTR", rig_params_.force_dtr);
|
settings_->setValue ("CATForceDTR", rig_params_.force_dtr);
|
||||||
@@ -1871,7 +1905,8 @@ void Configuration::impl::set_rig_invariants ()
|
|||||||
// makes no sense with rig as "None"
|
// makes no sense with rig as "None"
|
||||||
ui_->monitor_last_used_check_box->setEnabled (false);
|
ui_->monitor_last_used_check_box->setEnabled (false);
|
||||||
|
|
||||||
ui_->CAT_control_group_box->setEnabled (false);
|
ui_->catTab->setEnabled(false);
|
||||||
|
//ui_->CAT_control_group_box->setEnabled (false);
|
||||||
ui_->test_CAT_push_button->setEnabled (false);
|
ui_->test_CAT_push_button->setEnabled (false);
|
||||||
ui_->test_PTT_push_button->setEnabled (TransceiverFactory::PTT_method_DTR == ptt_method
|
ui_->test_PTT_push_button->setEnabled (TransceiverFactory::PTT_method_DTR == ptt_method
|
||||||
|| TransceiverFactory::PTT_method_RTS == ptt_method);
|
|| TransceiverFactory::PTT_method_RTS == ptt_method);
|
||||||
@@ -1880,7 +1915,8 @@ void Configuration::impl::set_rig_invariants ()
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
ui_->monitor_last_used_check_box->setEnabled (true);
|
ui_->monitor_last_used_check_box->setEnabled (true);
|
||||||
ui_->CAT_control_group_box->setEnabled (true);
|
ui_->catTab->setEnabled(true);
|
||||||
|
//ui_->CAT_control_group_box->setEnabled (true);
|
||||||
ui_->test_CAT_push_button->setEnabled (true);
|
ui_->test_CAT_push_button->setEnabled (true);
|
||||||
ui_->test_PTT_push_button->setEnabled (false);
|
ui_->test_PTT_push_button->setEnabled (false);
|
||||||
ui_->TX_audio_source_group_box->setEnabled (transceiver_factory_.has_CAT_PTT_mic_data (rig) && TransceiverFactory::PTT_method_CAT == ptt_method);
|
ui_->TX_audio_source_group_box->setEnabled (transceiver_factory_.has_CAT_PTT_mic_data (rig) && TransceiverFactory::PTT_method_CAT == ptt_method);
|
||||||
@@ -1931,7 +1967,9 @@ void Configuration::impl::set_rig_invariants ()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_->CAT_serial_port_parameters_group_box->setEnabled (is_serial_CAT);
|
ui_->CAT_serial_port_parameters_group_box->setEnabled (is_serial_CAT);
|
||||||
|
|
||||||
ui_->force_DTR_combo_box->setEnabled (is_serial_CAT
|
ui_->force_DTR_combo_box->setEnabled (is_serial_CAT
|
||||||
&& (cat_port != ptt_port
|
&& (cat_port != ptt_port
|
||||||
|| !ui_->PTT_DTR_radio_button->isEnabled ()
|
|| !ui_->PTT_DTR_radio_button->isEnabled ()
|
||||||
@@ -1948,8 +1986,39 @@ void Configuration::impl::set_rig_invariants ()
|
|||||||
|| TransceiverFactory::basic_transceiver_name_ != rig);
|
|| TransceiverFactory::basic_transceiver_name_ != rig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QStringList splitGroups(QString groupsString, bool filter){
|
||||||
|
QStringList groups;
|
||||||
|
if(groupsString.isEmpty()){
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(QString group, groupsString.split(",")){
|
||||||
|
auto g = group.trimmed();
|
||||||
|
if(filter && !g.startsWith("@")){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
groups.append(group.trimmed());
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups;
|
||||||
|
}
|
||||||
|
|
||||||
bool Configuration::impl::validate ()
|
bool Configuration::impl::validate ()
|
||||||
{
|
{
|
||||||
|
auto callsign = ui_->callsign_line_edit->text().trimmed();
|
||||||
|
if(!Varicode::isValidCallsign(callsign, nullptr) || callsign.startsWith("@")){
|
||||||
|
MessageBox::critical_message (this, tr ("The callsign format you provided is not supported"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(auto group, splitGroups(ui_->groups_line_edit->text(), false)){
|
||||||
|
if(!Varicode::isCompoundCallsign(group)){
|
||||||
|
MessageBox::critical_message (this, QString("%1 is not a valid group").arg(group));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ui_->sound_input_combo_box->currentIndex () < 0
|
if (ui_->sound_input_combo_box->currentIndex () < 0
|
||||||
&& !QAudioDeviceInfo::availableDevices (QAudio::AudioInput).empty ())
|
&& !QAudioDeviceInfo::availableDevices (QAudio::AudioInput).empty ())
|
||||||
{
|
{
|
||||||
@@ -2201,6 +2270,9 @@ void Configuration::impl::accept ()
|
|||||||
my_callsign_ = ui_->callsign_line_edit->text ();
|
my_callsign_ = ui_->callsign_line_edit->text ();
|
||||||
my_grid_ = ui_->grid_line_edit->text ();
|
my_grid_ = ui_->grid_line_edit->text ();
|
||||||
my_station_ = ui_->station_message_line_edit->text().toUpper();
|
my_station_ = ui_->station_message_line_edit->text().toUpper();
|
||||||
|
|
||||||
|
my_groups_ = splitGroups(ui_->groups_line_edit->text().toUpper().trimmed(), true);
|
||||||
|
|
||||||
cq_ = ui_->cq_message_line_edit->text().toUpper();
|
cq_ = ui_->cq_message_line_edit->text().toUpper();
|
||||||
reply_ = ui_->reply_message_line_edit->text().toUpper();
|
reply_ = ui_->reply_message_line_edit->text().toUpper();
|
||||||
my_qth_ = ui_->qth_message_line_edit->text().toUpper();
|
my_qth_ = ui_->qth_message_line_edit->text().toUpper();
|
||||||
@@ -2217,7 +2289,7 @@ void Configuration::impl::accept ()
|
|||||||
tx_qsy_allowed_ = ui_->tx_qsy_check_box->isChecked ();
|
tx_qsy_allowed_ = ui_->tx_qsy_check_box->isChecked ();
|
||||||
transmit_directed_ = ui_->transmit_directed_check_box->isChecked();
|
transmit_directed_ = ui_->transmit_directed_check_box->isChecked();
|
||||||
autoreply_off_at_startup_ = ui_->autoreply_off_check_box->isChecked ();
|
autoreply_off_at_startup_ = ui_->autoreply_off_check_box->isChecked ();
|
||||||
beacon_anywhere_ = ui_->beacon_anywhere_check_box->isChecked();
|
heartbeat_anywhere_ = ui_->heartbeat_anywhere_check_box->isChecked();
|
||||||
relay_disabled_ = ui_->relay_disabled_check_box->isChecked();
|
relay_disabled_ = ui_->relay_disabled_check_box->isChecked();
|
||||||
monitor_off_at_startup_ = ui_->monitor_off_check_box->isChecked ();
|
monitor_off_at_startup_ = ui_->monitor_off_check_box->isChecked ();
|
||||||
monitor_last_used_ = ui_->monitor_last_used_check_box->isChecked ();
|
monitor_last_used_ = ui_->monitor_last_used_check_box->isChecked ();
|
||||||
@@ -2225,15 +2297,16 @@ void Configuration::impl::accept ()
|
|||||||
log_as_DATA_ = ui_->log_as_RTTY_check_box->isChecked ();
|
log_as_DATA_ = ui_->log_as_RTTY_check_box->isChecked ();
|
||||||
report_in_comments_ = ui_->report_in_comments_check_box->isChecked ();
|
report_in_comments_ = ui_->report_in_comments_check_box->isChecked ();
|
||||||
prompt_to_log_ = ui_->prompt_to_log_check_box->isChecked ();
|
prompt_to_log_ = ui_->prompt_to_log_check_box->isChecked ();
|
||||||
clear_DX_ = ui_->clear_DX_check_box->isChecked ();
|
clear_callsign_ = ui_->clear_callsign_check_box->isChecked ();
|
||||||
miles_ = ui_->miles_check_box->isChecked ();
|
miles_ = ui_->miles_check_box->isChecked ();
|
||||||
quick_call_ = ui_->quick_call_check_box->isChecked ();
|
quick_call_ = ui_->quick_call_check_box->isChecked ();
|
||||||
disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked ();
|
disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked ();
|
||||||
beacon_ = ui_->beacon_spin_box->value ();
|
heartbeat_ = ui_->heartbeat_spin_box->value ();
|
||||||
watchdog_ = ui_->tx_watchdog_spin_box->value ();
|
watchdog_ = ui_->tx_watchdog_spin_box->value ();
|
||||||
data_mode_ = static_cast<DataMode> (ui_->TX_mode_button_group->checkedId ());
|
data_mode_ = static_cast<DataMode> (ui_->TX_mode_button_group->checkedId ());
|
||||||
save_directory_ = ui_->save_path_display_label->text ();
|
save_directory_ = ui_->save_path_display_label->text ();
|
||||||
azel_directory_ = ui_->azel_path_display_label->text ();
|
azel_directory_ = ui_->azel_path_display_label->text ();
|
||||||
|
sound_cq_path_ = ui_->sound_cq_path_display_label->text();
|
||||||
sound_dm_path_ = ui_->sound_dm_path_display_label->text();
|
sound_dm_path_ = ui_->sound_dm_path_display_label->text();
|
||||||
sound_am_path_ = ui_->sound_am_path_display_label->text();
|
sound_am_path_ = ui_->sound_am_path_display_label->text();
|
||||||
enable_VHF_features_ = ui_->enable_VHF_features_check_box->isChecked ();
|
enable_VHF_features_ = ui_->enable_VHF_features_check_box->isChecked ();
|
||||||
@@ -2631,6 +2704,15 @@ void Configuration::impl::on_station_message_line_edit_textChanged(QString const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Configuration::impl::on_groups_line_edit_textChanged(QString const &text)
|
||||||
|
{
|
||||||
|
QString upper = text.toUpper();
|
||||||
|
if(text != upper){
|
||||||
|
ui_->groups_line_edit->setText (upper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Configuration::impl::on_qth_message_line_edit_textChanged(QString const &text)
|
void Configuration::impl::on_qth_message_line_edit_textChanged(QString const &text)
|
||||||
{
|
{
|
||||||
QString upper = text.toUpper();
|
QString upper = text.toUpper();
|
||||||
@@ -2893,6 +2975,37 @@ void Configuration::impl::on_azel_path_select_push_button_clicked (bool /* check
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Configuration::impl::on_sound_cq_path_select_push_button_clicked(){
|
||||||
|
QStringList filters;
|
||||||
|
filters << "Audio files (*.wav)"
|
||||||
|
<< "Any files (*)";
|
||||||
|
|
||||||
|
QFileDialog fd {this, tr ("Sound File"), ui_->sound_cq_path_display_label->text ()};
|
||||||
|
fd.setNameFilters(filters);
|
||||||
|
|
||||||
|
if (fd.exec ()) {
|
||||||
|
if (fd.selectedFiles ().size ()) {
|
||||||
|
if(rig_params_.ptt_type == TransceiverFactory::PTT_method_VOX){
|
||||||
|
QMessageBox::warning(this, "Notifications Sounds Warning", "You have enabled notification sounds while using VOX. To avoid transmitting these notification sounds, please make sure your rig is using a different sound card than your system.");
|
||||||
|
}
|
||||||
|
ui_->sound_cq_path_display_label->setText(fd.selectedFiles().at(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Configuration::impl::on_sound_cq_path_test_push_button_clicked(){
|
||||||
|
auto path = ui_->sound_cq_path_display_label->text();
|
||||||
|
if(path.isEmpty()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSound::play(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Configuration::impl::on_sound_cq_path_reset_push_button_clicked(){
|
||||||
|
ui_->sound_cq_path_display_label->clear();
|
||||||
|
}
|
||||||
|
|
||||||
void Configuration::impl::on_sound_dm_path_select_push_button_clicked(){
|
void Configuration::impl::on_sound_dm_path_select_push_button_clicked(){
|
||||||
QStringList filters;
|
QStringList filters;
|
||||||
filters << "Audio files (*.wav)"
|
filters << "Audio files (*.wav)"
|
||||||
|
|||||||
+7
-3
@@ -98,6 +98,9 @@ public:
|
|||||||
QString my_callsign () const;
|
QString my_callsign () const;
|
||||||
QString my_grid () const;
|
QString my_grid () const;
|
||||||
QString my_station () const;
|
QString my_station () const;
|
||||||
|
QSet<QString> my_groups() const;
|
||||||
|
void addGroup(QString const &group);
|
||||||
|
void removeGroup(QString const &group);
|
||||||
int activity_aging() const;
|
int activity_aging() const;
|
||||||
int callsign_aging() const;
|
int callsign_aging() const;
|
||||||
QString my_qth () const;
|
QString my_qth () const;
|
||||||
@@ -120,7 +123,7 @@ public:
|
|||||||
void set_spot_to_reporting_networks (bool);
|
void set_spot_to_reporting_networks (bool);
|
||||||
bool transmit_directed() const;
|
bool transmit_directed() const;
|
||||||
bool autoreply_off_at_startup () const;
|
bool autoreply_off_at_startup () const;
|
||||||
bool beacon_anywhere() const;
|
bool heartbeat_anywhere() const;
|
||||||
bool relay_off() const;
|
bool relay_off() const;
|
||||||
bool monitor_off_at_startup () const;
|
bool monitor_off_at_startup () const;
|
||||||
bool monitor_last_used () const;
|
bool monitor_last_used () const;
|
||||||
@@ -130,11 +133,11 @@ public:
|
|||||||
bool insert_blank () const;
|
bool insert_blank () const;
|
||||||
bool DXCC () const;
|
bool DXCC () const;
|
||||||
bool ppfx() const;
|
bool ppfx() const;
|
||||||
bool clear_DX () const;
|
bool clear_callsign () const;
|
||||||
bool miles () const;
|
bool miles () const;
|
||||||
bool quick_call () const;
|
bool quick_call () const;
|
||||||
bool disable_TX_on_73 () const;
|
bool disable_TX_on_73 () const;
|
||||||
int beacon () const;
|
int heartbeat () const;
|
||||||
int watchdog () const;
|
int watchdog () const;
|
||||||
bool TX_messages () const;
|
bool TX_messages () const;
|
||||||
bool split_mode () const;
|
bool split_mode () const;
|
||||||
@@ -179,6 +182,7 @@ public:
|
|||||||
QStringListModel const * macros () const;
|
QStringListModel const * macros () const;
|
||||||
QDir save_directory () const;
|
QDir save_directory () const;
|
||||||
QDir azel_directory () const;
|
QDir azel_directory () const;
|
||||||
|
QString sound_cq_path() const;
|
||||||
QString sound_dm_path() const;
|
QString sound_dm_path() const;
|
||||||
QString sound_am_path() const;
|
QString sound_am_path() const;
|
||||||
QString rig_name () const;
|
QString rig_name () const;
|
||||||
|
|||||||
+3242
-2792
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,13 @@ require this so normally you can choose not to install libusb-1.0-dev
|
|||||||
but if you have a SoftRock USB or similar SDR that uses a custom USB
|
but if you have a SoftRock USB or similar SDR that uses a custom USB
|
||||||
interface then it is required.
|
interface then it is required.
|
||||||
|
|
||||||
|
On Debian based systems, install requirements like:
|
||||||
|
|
||||||
|
sudo apt install git cmake clang gfortran \
|
||||||
|
libfftw3-dev git libgfortran3 libusb-1.0-dev autoconf libtool \
|
||||||
|
texinfo qt5-default qtmultimedia5-dev libqt5multimedia5-plugins libqt5serialport5-dev \
|
||||||
|
libudev-dev pkg-config
|
||||||
|
|
||||||
The Hamlib library is required. Currently WSJT-X needs to be built
|
The Hamlib library is required. Currently WSJT-X needs to be built
|
||||||
using a forked version of the Hamlib git master. This fork contains
|
using a forked version of the Hamlib git master. This fork contains
|
||||||
patches not yet accepted by the Hamlib development team which are
|
patches not yet accepted by the Hamlib development team which are
|
||||||
|
|||||||
@@ -291,6 +291,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
|
|||||||
if (m_ic > i1) m_amp = 0.0;
|
if (m_ic > i1) m_amp = 0.0;
|
||||||
|
|
||||||
sample=qRound(m_amp*qSin(m_phi));
|
sample=qRound(m_amp*qSin(m_phi));
|
||||||
|
if(m_toneSpacing < 0) sample=qRound(m_amp*foxcom_.wave[m_ic]);
|
||||||
samples = load(postProcessSample(sample), samples);
|
samples = load(postProcessSample(sample), samples);
|
||||||
++framesGenerated;
|
++framesGenerated;
|
||||||
++m_ic;
|
++m_ic;
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
# Version number components
|
# Version number components
|
||||||
set (WSJTX_VERSION_MAJOR 0)
|
set (WSJTX_VERSION_MAJOR 0)
|
||||||
set (WSJTX_VERSION_MINOR 7)
|
set (WSJTX_VERSION_MINOR 10)
|
||||||
set (WSJTX_VERSION_PATCH 5)
|
set (WSJTX_VERSION_PATCH 1)
|
||||||
set (WSJTX_RC 0) # release candidate number, comment out or zero for development versions
|
set (WSJTX_RC 0) # release candidate number, comment out or zero for development versions
|
||||||
set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build
|
set (WSJTX_VERSION_IS_RELEASE 0) # set to 1 for final release build
|
||||||
|
|||||||
+29
-16
@@ -22,8 +22,9 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
|
|||||||
, message_ {string_.mid (column_qsoText + padding_).trimmed ()}
|
, message_ {string_.mid (column_qsoText + padding_).trimmed ()}
|
||||||
, is_standard_ {false}
|
, is_standard_ {false}
|
||||||
, frameType_(Varicode::FrameUnknown)
|
, frameType_(Varicode::FrameUnknown)
|
||||||
, isBeacon_(false)
|
, isHeartbeat_(false)
|
||||||
, isAlt_(false)
|
, isAlt_(false)
|
||||||
|
, bits_{0}
|
||||||
{
|
{
|
||||||
if(message_.length() >= 1) {
|
if(message_.length() >= 1) {
|
||||||
message_ = message_.left (21).remove (QRegularExpression {"[<>]"});
|
message_ = message_.left (21).remove (QRegularExpression {"[<>]"});
|
||||||
@@ -51,21 +52,29 @@ DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString
|
|||||||
grid_c_string += QByteArray {6 - grid_c_string.size (), ' '};
|
grid_c_string += QByteArray {6 - grid_c_string.size (), ' '};
|
||||||
is_standard_ = stdmsg_ (message_c_string.constData (), contest_mode_, grid_c_string.constData (), 22, 6);
|
is_standard_ = stdmsg_ (message_c_string.constData (), contest_mode_, grid_c_string.constData (), 22, 6);
|
||||||
|
|
||||||
// We're only going to unpack standard messages for CQs && beacons...
|
// We're only going to unpack standard messages for CQs && pings...
|
||||||
// TODO: jsherer - this is a hack for now...
|
// TODO: jsherer - this is a hack for now...
|
||||||
if(is_standard_){
|
if(is_standard_){
|
||||||
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
|
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bits_ = bits();
|
||||||
|
|
||||||
|
// don't even try to unpack -24dB frames...they are *very* likely to be false decodes...
|
||||||
|
if(snr() <= -24){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tryUnpack();
|
tryUnpack();
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodedText::DecodedText (QString const& js8callmessage):
|
DecodedText::DecodedText (QString const& js8callmessage, int bits):
|
||||||
frameType_(Varicode::FrameUnknown),
|
frameType_(Varicode::FrameUnknown),
|
||||||
message_(js8callmessage),
|
message_(js8callmessage),
|
||||||
isBeacon_(false),
|
isHeartbeat_(false),
|
||||||
isAlt_(false)
|
isAlt_(false),
|
||||||
|
bits_(bits)
|
||||||
{
|
{
|
||||||
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
|
is_standard_ = QRegularExpression("^(CQ|DE|QRZ)\\s").match(message_).hasMatch();
|
||||||
|
|
||||||
@@ -80,7 +89,11 @@ bool DecodedText::tryUnpack(){
|
|||||||
|
|
||||||
bool unpacked = false;
|
bool unpacked = false;
|
||||||
if(!unpacked){
|
if(!unpacked){
|
||||||
unpacked = tryUnpackBeacon();
|
unpacked = tryUnpackData();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!unpacked){
|
||||||
|
unpacked = tryUnpackHeartbeat();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!unpacked){
|
if(!unpacked){
|
||||||
@@ -91,14 +104,10 @@ bool DecodedText::tryUnpack(){
|
|||||||
unpacked = tryUnpackDirected();
|
unpacked = tryUnpackDirected();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!unpacked){
|
|
||||||
unpacked = tryUnpackData();
|
|
||||||
}
|
|
||||||
|
|
||||||
return unpacked;
|
return unpacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DecodedText::tryUnpackBeacon(){
|
bool DecodedText::tryUnpackHeartbeat(){
|
||||||
QString m = message().trimmed();
|
QString m = message().trimmed();
|
||||||
|
|
||||||
// directed calls will always be 12+ chars and contain no spaces.
|
// directed calls will always be 12+ chars and contain no spaces.
|
||||||
@@ -109,17 +118,17 @@ bool DecodedText::tryUnpackBeacon(){
|
|||||||
bool isAlt = false;
|
bool isAlt = false;
|
||||||
quint8 type = Varicode::FrameUnknown;
|
quint8 type = Varicode::FrameUnknown;
|
||||||
quint8 bits3 = 0;
|
quint8 bits3 = 0;
|
||||||
QStringList parts = Varicode::unpackBeaconMessage(m, &type, &isAlt, &bits3);
|
QStringList parts = Varicode::unpackHeartbeatMessage(m, &type, &isAlt, &bits3);
|
||||||
|
|
||||||
if(parts.isEmpty() || parts.length() < 2){
|
if(parts.isEmpty() || parts.length() < 2){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Beacon Alt Type
|
// Heartbeat Alt Type
|
||||||
// ---------------
|
// ---------------
|
||||||
// 1 0 BCN
|
// 1 0 HB
|
||||||
// 1 1 CQ
|
// 1 1 CQ
|
||||||
isBeacon_ = true;
|
isHeartbeat_ = true;
|
||||||
isAlt_ = isAlt;
|
isAlt_ = isAlt;
|
||||||
extra_ = parts.length() < 3 ? "" : parts.at(2);
|
extra_ = parts.length() < 3 ? "" : parts.at(2);
|
||||||
|
|
||||||
@@ -131,7 +140,7 @@ bool DecodedText::tryUnpackBeacon(){
|
|||||||
cmp.append(parts.at(1));
|
cmp.append(parts.at(1));
|
||||||
}
|
}
|
||||||
compound_ = cmp.join("/");
|
compound_ = cmp.join("/");
|
||||||
message_ = QString("%1: %2 %3 ").arg(compound_).arg(isAlt ? Varicode::cqString(bits3) : "BEACON").arg(extra_);
|
message_ = QString("%1: %2 %3 ").arg(compound_).arg(isAlt ? Varicode::cqString(bits3) : Varicode::hbString(bits3)).arg(extra_);
|
||||||
frameType_ = type;
|
frameType_ = type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -212,6 +221,10 @@ bool DecodedText::tryUnpackData(){
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
quint8 type = Varicode::FrameUnknown;
|
quint8 type = Varicode::FrameUnknown;
|
||||||
QString data = Varicode::unpackDataMessage(m, &type);
|
QString data = Varicode::unpackDataMessage(m, &type);
|
||||||
|
|
||||||
|
|||||||
+5
-4
@@ -31,10 +31,10 @@ class DecodedText
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit DecodedText (QString const& message, bool, QString const& my_grid);
|
explicit DecodedText (QString const& message, bool, QString const& my_grid);
|
||||||
explicit DecodedText (QString const& js8callmessage);
|
explicit DecodedText (QString const& js8callmessage, int bits);
|
||||||
|
|
||||||
bool tryUnpack();
|
bool tryUnpack();
|
||||||
bool tryUnpackBeacon();
|
bool tryUnpackHeartbeat();
|
||||||
bool tryUnpackCompound();
|
bool tryUnpackCompound();
|
||||||
bool tryUnpackDirected();
|
bool tryUnpackDirected();
|
||||||
bool tryUnpackData();
|
bool tryUnpackData();
|
||||||
@@ -45,7 +45,7 @@ public:
|
|||||||
QString compoundCall() const { return compound_; }
|
QString compoundCall() const { return compound_; }
|
||||||
bool isCompound() const { return !compound_.isEmpty(); }
|
bool isCompound() const { return !compound_.isEmpty(); }
|
||||||
|
|
||||||
bool isBeacon() const { return isBeacon_; }
|
bool isHeartbeat() const { return isHeartbeat_; }
|
||||||
bool isAlt() const { return isAlt_; }
|
bool isAlt() const { return isAlt_; }
|
||||||
|
|
||||||
QStringList directedMessage() const { return directed_; }
|
QStringList directedMessage() const { return directed_; }
|
||||||
@@ -99,7 +99,7 @@ private:
|
|||||||
column_qsoText = 22 };
|
column_qsoText = 22 };
|
||||||
|
|
||||||
quint8 frameType_;
|
quint8 frameType_;
|
||||||
bool isBeacon_;
|
bool isHeartbeat_;
|
||||||
bool isAlt_;
|
bool isAlt_;
|
||||||
QString compound_;
|
QString compound_;
|
||||||
QString extra_;
|
QString extra_;
|
||||||
@@ -109,6 +109,7 @@ private:
|
|||||||
bool contest_mode_;
|
bool contest_mode_;
|
||||||
QString message_;
|
QString message_;
|
||||||
bool is_standard_;
|
bool is_standard_;
|
||||||
|
int bits_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DECODEDTEXT_H
|
#endif // DECODEDTEXT_H
|
||||||
|
|||||||
@@ -107,17 +107,23 @@ QString JSC::decompress(Codeword const& bitvec){
|
|||||||
|
|
||||||
QList<quint64> bytes;
|
QList<quint64> bytes;
|
||||||
QList<int> separators;
|
QList<int> separators;
|
||||||
auto iter = bitvec.begin();
|
|
||||||
while(iter != bitvec.end()){
|
int i = 0;
|
||||||
quint64 byte = Varicode::bitsToInt(iter, 4);
|
int count = bitvec.count();
|
||||||
iter += 4;
|
while(i < count){
|
||||||
|
auto b = bitvec.mid(i, 4);
|
||||||
|
if(b.length() != 4){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
quint64 byte = Varicode::bitsToInt(b);
|
||||||
bytes.append(byte);
|
bytes.append(byte);
|
||||||
|
i += 4;
|
||||||
|
|
||||||
if(byte < s){
|
if(byte < s){
|
||||||
if(*iter){
|
if(count - i > 0 && bitvec.at(i)){
|
||||||
separators.append(bytes.length()-1);
|
separators.append(bytes.length()-1);
|
||||||
}
|
}
|
||||||
iter += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,8 +137,14 @@ QString JSC::decompress(Codeword const& bitvec){
|
|||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(start + k >= bytes.length()){
|
||||||
|
break;
|
||||||
|
}
|
||||||
j = j*s + bytes[start + k] + base[k];
|
j = j*s + bytes[start + k] + base[k];
|
||||||
|
|
||||||
|
if(j >= (int)JSC::size){
|
||||||
|
break;
|
||||||
|
}
|
||||||
auto word = QString(JSC::map[j].str);
|
auto word = QString(JSC::map[j].str);
|
||||||
|
|
||||||
out.append(word);
|
out.append(word);
|
||||||
|
|||||||
+1
-1
@@ -256665,7 +256665,7 @@ const Tuple JSC::list[262144] = {
|
|||||||
{"ALLCOCK", 7, 255496},
|
{"ALLCOCK", 7, 255496},
|
||||||
{"ALLCLASSIFIEDS", 14, 205858},
|
{"ALLCLASSIFIEDS", 14, 205858},
|
||||||
{"ALLCHIN", 7, 102391},
|
{"ALLCHIN", 7, 102391},
|
||||||
{"ALLCALL", 7, 81},
|
{"@ALLCALL", 7, 81},
|
||||||
{"ALLBUSINESS", 11, 110217},
|
{"ALLBUSINESS", 11, 110217},
|
||||||
{"ALLBRITTON", 10, 248655},
|
{"ALLBRITTON", 10, 248655},
|
||||||
{"ALLBRIGHT", 9, 249916},
|
{"ALLBRIGHT", 9, 249916},
|
||||||
|
|||||||
+1
-1
@@ -102,7 +102,7 @@ const Tuple JSC::map[262144] = {
|
|||||||
{"589", 3, 78},
|
{"589", 3, 78},
|
||||||
{"579", 3, 79},
|
{"579", 3, 79},
|
||||||
{"569", 3, 80},
|
{"569", 3, 80},
|
||||||
{"ALLCALL", 7, 81},
|
{"@ALLCALL", 7, 81},
|
||||||
{"BEACON", 6, 82},
|
{"BEACON", 6, 82},
|
||||||
{"CQCQCQ", 6, 83},
|
{"CQCQCQ", 6, 83},
|
||||||
{"CPY?", 4, 84},
|
{"CPY?", 4, 84},
|
||||||
|
|||||||
+8
-60
@@ -60,25 +60,15 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
|
|||||||
if(mod(params%nranera,2).eq.1) ntrials=3*10**(params%nranera/2)
|
if(mod(params%nranera,2).eq.1) ntrials=3*10**(params%nranera/2)
|
||||||
if(params%nranera.eq.0) ntrials=0
|
if(params%nranera.eq.0) ntrials=0
|
||||||
|
|
||||||
nfail=0
|
10 nfail=0
|
||||||
10 if (params%nagain) then
|
|
||||||
open(13,file=trim(temp_dir)//'/decoded.txt',status='unknown', &
|
|
||||||
position='append',iostat=ios)
|
|
||||||
else
|
|
||||||
open(13,file=trim(temp_dir)//'/decoded.txt',status='unknown',iostat=ios)
|
|
||||||
endif
|
|
||||||
if(params%nmode.eq.8) then
|
if(params%nmode.eq.8) then
|
||||||
inquire(file=trim(temp_dir)//'/houndcallers.txt',exist=ex)
|
c2fox=' '
|
||||||
if(.not.ex) then
|
g2fox=' '
|
||||||
c2fox=' '
|
nsnrfox=-99
|
||||||
g2fox=' '
|
nfreqfox=-99
|
||||||
nsnrfox=-99
|
n30z=0
|
||||||
nfreqfox=-99
|
nwrap=0
|
||||||
n30z=0
|
nfox=0
|
||||||
nwrap=0
|
|
||||||
nfox=0
|
|
||||||
endif
|
|
||||||
open(19,file=trim(temp_dir)//'/houndcallers.txt',status='unknown')
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if(ios.ne.0) then
|
if(ios.ne.0) then
|
||||||
@@ -103,35 +93,6 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
|
|||||||
n30min=minval(n30fox(1:nfox))
|
n30min=minval(n30fox(1:nfox))
|
||||||
n30max=maxval(n30fox(1:nfox))
|
n30max=maxval(n30fox(1:nfox))
|
||||||
endif
|
endif
|
||||||
j=0
|
|
||||||
rewind 19
|
|
||||||
if(nfox.eq.0) then
|
|
||||||
endfile 19
|
|
||||||
rewind 19
|
|
||||||
else
|
|
||||||
do i=1,nfox
|
|
||||||
n=n30fox(i)
|
|
||||||
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
|
|
||||||
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,m
|
|
||||||
1004 format(a12,1x,a4,i5,i6,i7,i3)
|
|
||||||
endif
|
|
||||||
enddo
|
|
||||||
nfox=j
|
|
||||||
flush(19)
|
|
||||||
endif
|
|
||||||
go to 800
|
go to 800
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -255,8 +216,6 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
|
|||||||
write(*,1010) nsynced,ndecoded
|
write(*,1010) nsynced,ndecoded
|
||||||
1010 format('<DecodeFinished>',2i4)
|
1010 format('<DecodeFinished>',2i4)
|
||||||
call flush(6)
|
call flush(6)
|
||||||
close(13)
|
|
||||||
close(19)
|
|
||||||
if(params%nmode.eq.4 .or. params%nmode.eq.65) close(14)
|
if(params%nmode.eq.4 .or. params%nmode.eq.65) close(14)
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -369,9 +328,6 @@ contains
|
|||||||
write(*,1009) params%nutc,snr,dt,freq,csync,decoded,nft
|
write(*,1009) params%nutc,snr,dt,freq,csync,decoded,nft
|
||||||
1009 format(i4.4,i4,f5.1,i5,1x,a2,1x,a22,i2)
|
1009 format(i4.4,i4,f5.1,i5,1x,a2,1x,a22,i2)
|
||||||
endif
|
endif
|
||||||
write(13,1011) params%nutc,nint(sync),snr,dt,float(freq),drift, &
|
|
||||||
decoded,nft
|
|
||||||
1011 format(i4.4,i4,i5,f6.2,f8.0,i4,3x,a22,' QRA64',i3)
|
|
||||||
go to 100
|
go to 100
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -415,9 +371,6 @@ contains
|
|||||||
write(*,1010) params%nutc,snr,dt,freq,csync,decoded,cflags
|
write(*,1010) params%nutc,snr,dt,freq,csync,decoded,cflags
|
||||||
1010 format(i4.4,i4,f5.1,i5,1x,a2,1x,a22,1x,a3)
|
1010 format(i4.4,i4,f5.1,i5,1x,a2,1x,a22,1x,a3)
|
||||||
endif
|
endif
|
||||||
write(13,1012) params%nutc,nint(sync),snr,dt,float(freq),drift, &
|
|
||||||
decoded,ft,nsum,nsmo
|
|
||||||
1012 format(i4.4,i4,i5,f6.2,f8.0,i4,3x,a22,' JT65',3i3)
|
|
||||||
|
|
||||||
100 call flush(6)
|
100 call flush(6)
|
||||||
|
|
||||||
@@ -443,8 +396,6 @@ contains
|
|||||||
!$omp critical(decode_results)
|
!$omp critical(decode_results)
|
||||||
write(*,1000) params%nutc,snr,dt,nint(freq),decoded
|
write(*,1000) params%nutc,snr,dt,nint(freq),decoded
|
||||||
1000 format(i4.4,i4,f5.1,i5,1x,'@ ',1x,a22)
|
1000 format(i4.4,i4,f5.1,i5,1x,'@ ',1x,a22)
|
||||||
write(13,1002) params%nutc,nint(sync),snr,dt,freq,drift,decoded
|
|
||||||
1002 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a22,' JT9')
|
|
||||||
call flush(6)
|
call flush(6)
|
||||||
!$omp end critical(decode_results)
|
!$omp end critical(decode_results)
|
||||||
select type(this)
|
select type(this)
|
||||||
@@ -503,8 +454,6 @@ contains
|
|||||||
1000 format(i6.6,i4,f5.1,i5,' ~ ',1x,a22,1x,a2)
|
1000 format(i6.6,i4,f5.1,i5,' ~ ',1x,a22,1x,a2)
|
||||||
if(i0.gt.0) write(*,1001) params%nutc,snr,dt,nint(freq),decoded0
|
if(i0.gt.0) write(*,1001) params%nutc,snr,dt,nint(freq),decoded0
|
||||||
1001 format(i6.6,i4,f5.1,i5,' ~ ',1x,a37)
|
1001 format(i6.6,i4,f5.1,i5,' ~ ',1x,a37)
|
||||||
write(13,1002) params%nutc,nint(sync),snr,dt,freq,0,decoded0
|
|
||||||
1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' FT8')
|
|
||||||
|
|
||||||
i1=index(decoded0,' ')
|
i1=index(decoded0,' ')
|
||||||
i2=i1 + index(decoded0(i1+1:),' ')
|
i2=i1 + index(decoded0(i1+1:),' ')
|
||||||
@@ -538,7 +487,6 @@ contains
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
call flush(6)
|
call flush(6)
|
||||||
call flush(13)
|
|
||||||
|
|
||||||
select type(this)
|
select type(this)
|
||||||
type is (counting_ft8_decoder)
|
type is (counting_ft8_decoder)
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
Quick Start for DXpedition Mode
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
These notes are intended for operators already familiar with WSJT-X
|
|
||||||
and FT8 mode. QSOs between the Dxpedition ("Fox") and other stations
|
|
||||||
("Hounds") are completed with as little as one transmission per Hound,
|
|
||||||
as in the following examples:
|
|
||||||
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
Fox (300-600 Hz) Hounds
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
1. CQ KH1DX AJ10
|
|
||||||
2. KH1DX K1ABC FN42, KH1DX W9XYZ EN37, ...
|
|
||||||
3. K1ABC KH1DX -13
|
|
||||||
4. KH1DX K1ABC R-11
|
|
||||||
5. K1ABC RR73; W9XYZ <KH1DX> -17
|
|
||||||
6. KH1DX W9XYZ R-16
|
|
||||||
7. W9XYZ RR73; G4AAA <KH1DX> -09
|
|
||||||
8. ...
|
|
||||||
----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
Everybody sets dial frequency to an agreed number and uses CAT control
|
|
||||||
with Split Operation (either *Rig* or *Fake It*). Fox transmits up to
|
|
||||||
5 signals simultaneously, at audio frequencies 300, 360, ... 540
|
|
||||||
Hz. Hounds make initial calls (e.g., line 2 above) anywhere in the
|
|
||||||
range 1000 - 4000 Hz. They send "R+rpt" 350 Hz above the frequency
|
|
||||||
where Fox called them.
|
|
||||||
|
|
||||||
|
|
||||||
INSTRUCTIONS FOR FOX
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
1. Start WSJT-X in FT8 mode. Select *Fox* on the *Settings ->
|
|
||||||
Advanced tab*. On the main window, check *Tx even/1st*, *Auto Seq*,
|
|
||||||
and *Hold Tx Freq*; uncheck *Call 1st*. Set *Tx 300 Hz* and select
|
|
||||||
Tab 3.
|
|
||||||
|
|
||||||
2. In Fox mode the left window (called "Band Activity" in normal FT8
|
|
||||||
mode) is labeled "Stations calling DXpedition <MyCall>". It will be
|
|
||||||
filled with a sorted list of calling Hounds. You can sort by Call,
|
|
||||||
Grid, S/N, Distance, or Random order by using the comboBox at top
|
|
||||||
right of Tab 3. You can limit the displayed Hound callsigns to those
|
|
||||||
no stronger than *Max dB*. Fox might use this feature to discourage
|
|
||||||
Hounds from engaging in a QRO arms race.
|
|
||||||
|
|
||||||
3. *N Slots* sets the number of simultaneous Fox signals to be used.
|
|
||||||
Fox carries out as many as *N Slots* QSOs simultaneously.
|
|
||||||
|
|
||||||
4. *Repeats* sets the maximum number of repeat transmissions of the
|
|
||||||
same message. A QSO is aborted when this number would be exceeded.
|
|
||||||
|
|
||||||
5. The *CQ* comboBox on Tab 3 offers a selection of directed CQ
|
|
||||||
messages. *Reset* clears the QSO queue.
|
|
||||||
|
|
||||||
6. The Fox operator's main task is to select Hounds to be called and
|
|
||||||
worked. The text box on Tab 3 holds the "QSO queue": a list of Hound
|
|
||||||
calls to be worked. Hit Enter to select the top callsign from the
|
|
||||||
sorted list of callers (left window), or double-click on any
|
|
||||||
particular call. Either actiion moves that Hound into the "QSO
|
|
||||||
queue".
|
|
||||||
|
|
||||||
7. The right window displays decodes of signals below 1000 Hz.
|
|
||||||
Normally these should include only Hound messages containing "R+rpt"
|
|
||||||
and Fox's own transmissions.
|
|
||||||
|
|
||||||
8. To get things started, toggle *Enable Tx* to red. If a Hound call
|
|
||||||
is available in the QSO queue, that station will be called. If the
|
|
||||||
QSO queue is empty, Fox calls CQ.
|
|
||||||
|
|
||||||
9. If you're using Nslots = 2 or higher, your signal no longer has
|
|
||||||
a constant envelope. To avoid producing intermod sidebands you need
|
|
||||||
to ensure linearity in your Tx system. One way to get things about right
|
|
||||||
is to use the WSJT-X *Tune* button to generate a pure tone. Reduce the
|
|
||||||
Tx audio level until your power output decreases by 10% or so. Use this
|
|
||||||
level for your Fox transmissions.
|
|
||||||
|
|
||||||
NOTE: If you are generating Nslots signals, the average power in each one
|
|
||||||
will be 1/Nslots^2 of its normal value for single-signal transmissions.
|
|
||||||
|
|
||||||
Nslots Relative dB
|
|
||||||
-------------------
|
|
||||||
1 0
|
|
||||||
2 -6
|
|
||||||
3 -9.5
|
|
||||||
4 -12
|
|
||||||
5 -14
|
|
||||||
|
|
||||||
|
|
||||||
The following features are not yet implemented for Fox:
|
|
||||||
|
|
||||||
1. Enforce all required settings
|
|
||||||
2. Tx message timeout
|
|
||||||
3. Manual abort of selected QSO
|
|
||||||
4. All Tx and Rx messages to all.txt
|
|
||||||
5. Additional sort criteria for Hound calls
|
|
||||||
6. Selectable timeout for keeping Hounds in the sorted list
|
|
||||||
7. Display number of active callers
|
|
||||||
8. Display QSO rate
|
|
||||||
|
|
||||||
|
|
||||||
INSTRUCTIONS FOR HOUND
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
1. Start WSJT-X in FT8 mode. Select *Hound* On the *Settings ->
|
|
||||||
Advanced* tab. On the main window check *Auto Seq* and uncheck *Tx
|
|
||||||
even/1st*, *Call 1st*, and *Hold Tx Freq*. Set *Tx nnnn Hz* to some
|
|
||||||
frequency between 1000 and 4000 Hz, and select *Tab 1*. Enter Fox's
|
|
||||||
callsign and locator in DX Call and DX Grid, select Tx1, and start
|
|
||||||
*Monitor*.
|
|
||||||
|
|
||||||
2. When you have copied Fox, hit *Enable Tx* to call him. You may
|
|
||||||
keep calling until he answers. You may wish to move your TxFreq
|
|
||||||
around, hoping to find a clear calling frequency.
|
|
||||||
|
|
||||||
3. When you are called by Fox with a signal report, your next
|
|
||||||
transmission will automatically be sent as Tx3 ("R+rpt"). When Fox
|
|
||||||
receives that message he responds with "RR73", and your QSO is
|
|
||||||
complete!
|
|
||||||
|
|
||||||
|
|
||||||
The following features are not yet implemented for Hound:
|
|
||||||
|
|
||||||
1. Force all required settings
|
|
||||||
2. React properly to directed CQs from Fox
|
|
||||||
3. Disable Tx2, 4, 5, 6
|
|
||||||
4. For Tx1, enforce TxFreq >= 1000 Hz
|
|
||||||
@@ -16,7 +16,7 @@ subroutine chkcrc12a(decoded,nbadcrc)
|
|||||||
i1Dec8BitBytes(10)=iand(i1Dec8BitBytes(10),128+64+32)
|
i1Dec8BitBytes(10)=iand(i1Dec8BitBytes(10),128+64+32)
|
||||||
i1Dec8BitBytes(11)=0
|
i1Dec8BitBytes(11)=0
|
||||||
icrc12=crc12(c_loc(i1Dec8BitBytes),11) !CRC12 computed from 75 msg bits
|
icrc12=crc12(c_loc(i1Dec8BitBytes),11) !CRC12 computed from 75 msg bits
|
||||||
! icrc12=xor(icrc12, 41) ! TODO: jsherer - could change the crc here
|
icrc12=xor(icrc12, 42) ! TODO: jsherer - could change the crc here
|
||||||
|
|
||||||
nbadcrc=1
|
nbadcrc=1
|
||||||
if(ncrc12.eq.icrc12) nbadcrc=0
|
if(ncrc12.eq.icrc12) nbadcrc=0
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ subroutine extractmessage174(decoded,msgreceived,ncrcflag)
|
|||||||
i1Dec8BitBytes(10)=iand(i1Dec8BitBytes(10),128+64+32)
|
i1Dec8BitBytes(10)=iand(i1Dec8BitBytes(10),128+64+32)
|
||||||
i1Dec8BitBytes(11)=0
|
i1Dec8BitBytes(11)=0
|
||||||
icrc12=crc12(c_loc(i1Dec8BitBytes),11) !CRC12 computed from 75 msg bits
|
icrc12=crc12(c_loc(i1Dec8BitBytes),11) !CRC12 computed from 75 msg bits
|
||||||
! icrc12=xor(icrc12, 41) ! TODO: jsherer - could change the crc here
|
icrc12=xor(icrc12, 42) ! TODO: jsherer - could change the crc here
|
||||||
|
|
||||||
if(ncrc12.eq.icrc12 .or. sum(decoded(57:87)).eq.0) then !### Kludge ###
|
if(ncrc12.eq.icrc12) then ! .or. sum(decoded(57:87)).eq.0) then !### Kludge ###
|
||||||
! CRC12 checks out --- unpack 72-bit message
|
! CRC12 checks out --- unpack 72-bit message
|
||||||
do ibyte=1,12
|
do ibyte=1,12
|
||||||
itmp=0
|
itmp=0
|
||||||
|
|||||||
@@ -5,13 +5,21 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
|
|||||||
parameter (NMAX=15*12000,NSPS=1920)
|
parameter (NMAX=15*12000,NSPS=1920)
|
||||||
parameter (NFFT1=192000,NFFT2=3200) !192000/60 = 3200
|
parameter (NFFT1=192000,NFFT2=3200) !192000/60 = 3200
|
||||||
|
|
||||||
logical newdat
|
logical newdat,first
|
||||||
complex c1(0:NFFT2-1)
|
complex c1(0:NFFT2-1)
|
||||||
complex cx(0:NFFT1/2)
|
complex cx(0:NFFT1/2)
|
||||||
real dd(NMAX),x(NFFT1)
|
real dd(NMAX),x(NFFT1),taper(0:100)
|
||||||
equivalence (x,cx)
|
equivalence (x,cx)
|
||||||
save cx
|
data first/.true./
|
||||||
|
save cx,first,taper
|
||||||
|
|
||||||
|
if(first) then
|
||||||
|
pi=4.0*atan(1.0)
|
||||||
|
do i=0,100
|
||||||
|
taper(i)=0.5*(1.0+cos(i*pi/100))
|
||||||
|
enddo
|
||||||
|
first=.false.
|
||||||
|
endif
|
||||||
if(newdat) then
|
if(newdat) then
|
||||||
! Data in dd have changed, recompute the long FFT
|
! Data in dd have changed, recompute the long FFT
|
||||||
x(1:NMAX)=dd
|
x(1:NMAX)=dd
|
||||||
@@ -23,9 +31,9 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
|
|||||||
df=12000.0/NFFT1
|
df=12000.0/NFFT1
|
||||||
baud=12000.0/NSPS
|
baud=12000.0/NSPS
|
||||||
i0=nint(f0/df)
|
i0=nint(f0/df)
|
||||||
ft=f0+8.0*baud
|
ft=f0+8.5*baud
|
||||||
it=min(nint(ft/df),NFFT1/2)
|
it=min(nint(ft/df),NFFT1/2)
|
||||||
fb=f0-1.0*baud
|
fb=f0-1.5*baud
|
||||||
ib=max(1,nint(fb/df))
|
ib=max(1,nint(fb/df))
|
||||||
k=0
|
k=0
|
||||||
c1=0.
|
c1=0.
|
||||||
@@ -33,6 +41,8 @@ subroutine ft8_downsample(dd,newdat,f0,c1)
|
|||||||
c1(k)=cx(i)
|
c1(k)=cx(i)
|
||||||
k=k+1
|
k=k+1
|
||||||
enddo
|
enddo
|
||||||
|
c1(0:100)=c1(0:100)*taper(100:0:-1)
|
||||||
|
c1(k-1-100:k-1)=c1(k-1-100:k-1)*taper
|
||||||
c1=cshift(c1,i0-ib)
|
c1=cshift(c1,i0-ib)
|
||||||
call four2a(c1,NFFT2,1,1,1) !c2c FFT back to time domain
|
call four2a(c1,NFFT2,1,1,1) !c2c FFT back to time domain
|
||||||
fac=1.0/sqrt(float(NFFT1)*NFFT2)
|
fac=1.0/sqrt(float(NFFT1)*NFFT2)
|
||||||
|
|||||||
+4
-3
@@ -28,7 +28,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
|
|||||||
integer nappasses(0:5) !Number of decoding passes to use for each QSO state
|
integer nappasses(0:5) !Number of decoding passes to use for each QSO state
|
||||||
integer naptypes(0:5,4) ! (nQSOProgress, decoding pass) maximum of 4 passes for now
|
integer naptypes(0:5,4) ! (nQSOProgress, decoding pass) maximum of 4 passes for now
|
||||||
integer*1, target:: i1hiscall(12)
|
integer*1, target:: i1hiscall(12)
|
||||||
complex cd0(3200)
|
complex cd0(0:3199)
|
||||||
complex ctwk(32)
|
complex ctwk(32)
|
||||||
complex csymb(32)
|
complex csymb(32)
|
||||||
logical first,newdat,lsubtract,lapon,lapcqonly,nagain
|
logical first,newdat,lsubtract,lapon,lapcqonly,nagain
|
||||||
@@ -126,7 +126,8 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
|
|||||||
do k=1,NN
|
do k=1,NN
|
||||||
i1=ibest+(k-1)*32
|
i1=ibest+(k-1)*32
|
||||||
csymb=cmplx(0.0,0.0)
|
csymb=cmplx(0.0,0.0)
|
||||||
if( i1.ge.1 .and. i1+31 .le. NP2 ) csymb=cd0(i1:i1+31)
|
!if( i1.ge.1 .and. i1+31 .le. NP2 ) csymb=cd0(i1:i1+31)
|
||||||
|
if( i1.ge.0 .and. i1+31 .le. NP2-1 ) csymb=cd0(i1:i1+31)
|
||||||
call four2a(csymb,32,1,-1,1)
|
call four2a(csymb,32,1,-1,1)
|
||||||
s2(0:7,k)=abs(csymb(1:8))/1e3
|
s2(0:7,k)=abs(csymb(1:8))/1e3
|
||||||
enddo
|
enddo
|
||||||
@@ -181,7 +182,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, &
|
|||||||
bmetap(i2)=r2
|
bmetap(i2)=r2
|
||||||
bmetap(i1)=r1
|
bmetap(i1)=r1
|
||||||
! Max log metric
|
! Max log metric
|
||||||
psl=log(ps)
|
psl=log(ps+1e-32)
|
||||||
r1=max(psl(1),psl(3),psl(5),psl(7))-max(psl(0),psl(2),psl(4),psl(6))
|
r1=max(psl(1),psl(3),psl(5),psl(7))-max(psl(0),psl(2),psl(4),psl(6))
|
||||||
r2=max(psl(2),psl(3),psl(6),psl(7))-max(psl(0),psl(1),psl(4),psl(5))
|
r2=max(psl(2),psl(3),psl(6),psl(7))-max(psl(0),psl(1),psl(4),psl(5))
|
||||||
r4=max(psl(4),psl(5),psl(6),psl(7))-max(psl(0),psl(1),psl(2),psl(3))
|
r4=max(psl(4),psl(5),psl(6),psl(7))-max(psl(0),psl(1),psl(2),psl(3))
|
||||||
|
|||||||
+1
-1
@@ -38,7 +38,7 @@ subroutine genft8(msg,mygrid,bcontest,i3bit,msgsent,msgbits,itone)
|
|||||||
i1Msg8BitBytes(10)=iand(i1Msg8BitBytes(10),128+64+32)
|
i1Msg8BitBytes(10)=iand(i1Msg8BitBytes(10),128+64+32)
|
||||||
i1Msg8BitBytes(11)=0
|
i1Msg8BitBytes(11)=0
|
||||||
icrc12=crc12(c_loc(i1Msg8BitBytes),11)
|
icrc12=crc12(c_loc(i1Msg8BitBytes),11)
|
||||||
! icrc12=xor(icrc12, 41) ! TODO: jsherer - could change the crc here
|
icrc12=xor(icrc12, 42) ! TODO: jsherer - could change the crc here
|
||||||
|
|
||||||
! For reference, here's how to check the CRC
|
! For reference, here's how to check the CRC
|
||||||
! i1Msg8BitBytes(10)=icrc12/256
|
! i1Msg8BitBytes(10)=icrc12/256
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ allocate ( rxdata(N), llr(N) )
|
|||||||
|
|
||||||
i1Msg8BitBytes(10:11)=0
|
i1Msg8BitBytes(10:11)=0
|
||||||
checksum = crc12 (c_loc (i1Msg8BitBytes), 11)
|
checksum = crc12 (c_loc (i1Msg8BitBytes), 11)
|
||||||
! checksum = xor(checksum, 41) ! TODO: jsherer - could change the crc here
|
checksum = xor(checksum, 42) ! TODO: jsherer - could change the crc here
|
||||||
! For reference, the next 3 lines show how to check the CRC
|
! For reference, the next 3 lines show how to check the CRC
|
||||||
i1Msg8BitBytes(10)=checksum/256
|
i1Msg8BitBytes(10)=checksum/256
|
||||||
i1Msg8BitBytes(11)=iand (checksum,255)
|
i1Msg8BitBytes(11)=iand (checksum,255)
|
||||||
|
|||||||
+12
-19
@@ -37,11 +37,6 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand,sbase)
|
|||||||
savg=savg + s(1:NH1,j) !Average spectrum
|
savg=savg + s(1:NH1,j) !Average spectrum
|
||||||
enddo
|
enddo
|
||||||
call baseline(savg,nfa,nfb,sbase)
|
call baseline(savg,nfa,nfb,sbase)
|
||||||
! savg=savg/NHSYM
|
|
||||||
! do i=1,NH1
|
|
||||||
! write(51,3051) i*df,savg(i),db(savg(i))
|
|
||||||
!3051 format(f10.3,e12.3,f12.3)
|
|
||||||
! enddo
|
|
||||||
|
|
||||||
ia=max(1,nint(nfa/df))
|
ia=max(1,nint(nfa/df))
|
||||||
ib=nint(nfb/df)
|
ib=nint(nfb/df)
|
||||||
@@ -49,6 +44,9 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand,sbase)
|
|||||||
nfos=NFFT1/NSPS ! # frequency bin oversampling factor
|
nfos=NFFT1/NSPS ! # frequency bin oversampling factor
|
||||||
jstrt=0.5/tstep
|
jstrt=0.5/tstep
|
||||||
|
|
||||||
|
candidate0=0.
|
||||||
|
k=0
|
||||||
|
|
||||||
do i=ia,ib
|
do i=ia,ib
|
||||||
do j=-JZ,+JZ
|
do j=-JZ,+JZ
|
||||||
ta=0.
|
ta=0.
|
||||||
@@ -95,20 +93,18 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand,sbase)
|
|||||||
iz=ib-ia+1
|
iz=ib-ia+1
|
||||||
call indexx(red(ia:ib),iz,indx)
|
call indexx(red(ia:ib),iz,indx)
|
||||||
ibase=indx(nint(0.40*iz)) - 1 + ia
|
ibase=indx(nint(0.40*iz)) - 1 + ia
|
||||||
|
if(ibase.lt.1) ibase=1
|
||||||
|
if(ibase.gt.nh1) ibase=nh1
|
||||||
base=red(ibase)
|
base=red(ibase)
|
||||||
red=red/base
|
red=red/base
|
||||||
|
|
||||||
candidate0=0.
|
do i=1,min(200,iz)
|
||||||
k=0
|
n=ia + indx(iz+1-i) - 1
|
||||||
do i=1,200
|
if(red(n).lt.syncmin.or.isnan(red(n)).or.k.eq.200) exit
|
||||||
ji=iz+1-1
|
k=k+1
|
||||||
if(ji.eq.0) exit
|
candidate0(1,k)=n*df
|
||||||
n=ia + indx(ji) - 1
|
candidate0(2,k)=(jpeak(n)-1)*tstep
|
||||||
if(red(n).lt.syncmin) exit
|
candidate0(3,k)=red(n)
|
||||||
if(k.lt.200) k=k+1
|
|
||||||
candidate0(1,k)=n*df
|
|
||||||
candidate0(2,k)=(jpeak(n)-1)*tstep
|
|
||||||
candidate0(3,k)=red(n)
|
|
||||||
enddo
|
enddo
|
||||||
ncand=k
|
ncand=k
|
||||||
|
|
||||||
@@ -123,9 +119,6 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,s,candidate,ncand,sbase)
|
|||||||
if(candidate0(3,i).lt.candidate0(3,j)) candidate0(3,i)=0.
|
if(candidate0(3,i).lt.candidate0(3,j)) candidate0(3,i)=0.
|
||||||
endif
|
endif
|
||||||
enddo
|
enddo
|
||||||
! write(*,3001) i,candidate0(1,i-1),candidate0(1,i),candidate0(3,i-1), &
|
|
||||||
! candidate0(3,i)
|
|
||||||
!3001 format(i2,4f8.1)
|
|
||||||
endif
|
endif
|
||||||
enddo
|
enddo
|
||||||
|
|
||||||
|
|||||||
+9
-18
@@ -100,6 +100,7 @@ void ADIF::load()
|
|||||||
add (extractField (record, "CALL")
|
add (extractField (record, "CALL")
|
||||||
, extractField (record, "BAND")
|
, extractField (record, "BAND")
|
||||||
, extractField (record, "MODE")
|
, extractField (record, "MODE")
|
||||||
|
, extractField (record, "SUBMODE")
|
||||||
, extractField (record, "QSO_DATE"));
|
, extractField (record, "QSO_DATE"));
|
||||||
}
|
}
|
||||||
inputFile.close ();
|
inputFile.close ();
|
||||||
@@ -107,12 +108,13 @@ void ADIF::load()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ADIF::add(QString const& call, QString const& band, QString const& mode, QString const& date)
|
void ADIF::add(QString const& call, QString const& band, QString const& mode, QString const& submode, QString const& date)
|
||||||
{
|
{
|
||||||
QSO q;
|
QSO q;
|
||||||
q.call = call;
|
q.call = call;
|
||||||
q.band = band;
|
q.band = band;
|
||||||
q.mode = mode;
|
q.mode = mode;
|
||||||
|
q.submode = submode;
|
||||||
q.date = date;
|
q.date = date;
|
||||||
if (q.call.size ())
|
if (q.call.size ())
|
||||||
{
|
{
|
||||||
@@ -121,8 +123,8 @@ void ADIF::add(QString const& call, QString const& band, QString const& mode, QS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// return true if in the log same band and mode (where JT65 == JT9)
|
// return true if in the log same band
|
||||||
bool ADIF::match(QString const& call, QString const& band, QString const& mode) const
|
bool ADIF::match(QString const& call, QString const& band) const
|
||||||
{
|
{
|
||||||
QList<QSO> qsos = _data.values(call);
|
QList<QSO> qsos = _data.values(call);
|
||||||
if (qsos.size()>0)
|
if (qsos.size()>0)
|
||||||
@@ -134,20 +136,6 @@ bool ADIF::match(QString const& call, QString const& band, QString const& mode)
|
|||||||
|| (band=="")
|
|| (band=="")
|
||||||
|| (q.band==""))
|
|| (q.band==""))
|
||||||
{
|
{
|
||||||
if (
|
|
||||||
(
|
|
||||||
((mode.compare("JT65",Qt::CaseInsensitive)==0) ||
|
|
||||||
(mode.compare("JT9",Qt::CaseInsensitive)==0) ||
|
|
||||||
(mode.compare("FT8",Qt::CaseInsensitive)==0))
|
|
||||||
&&
|
|
||||||
((q.mode.compare("JT65",Qt::CaseInsensitive)==0) ||
|
|
||||||
(q.mode.compare("JT9",Qt::CaseInsensitive)==0) ||
|
|
||||||
(q.mode.compare("FT8",Qt::CaseInsensitive)==0))
|
|
||||||
)
|
|
||||||
|| (mode.compare(q.mode,Qt::CaseInsensitive)==0)
|
|
||||||
|| (mode=="")
|
|
||||||
|| (q.mode=="")
|
|
||||||
)
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,7 +162,7 @@ int ADIF::getCount() const
|
|||||||
return _data.size();
|
return _data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode
|
QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& submode
|
||||||
, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn
|
, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn
|
||||||
, QDateTime const& dateTimeOff, QString const& band, QString const& comments
|
, QDateTime const& dateTimeOff, QString const& band, QString const& comments
|
||||||
, QString const& name, QString const& strDialFreq, QString const& m_myCall
|
, QString const& name, QString const& strDialFreq, QString const& m_myCall
|
||||||
@@ -184,6 +172,9 @@ QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QStri
|
|||||||
t = "<call:" + QString::number(hisCall.length()) + ">" + hisCall;
|
t = "<call:" + QString::number(hisCall.length()) + ">" + hisCall;
|
||||||
t += " <gridsquare:" + QString::number(hisGrid.length()) + ">" + hisGrid;
|
t += " <gridsquare:" + QString::number(hisGrid.length()) + ">" + hisGrid;
|
||||||
t += " <mode:" + QString::number(mode.length()) + ">" + mode;
|
t += " <mode:" + QString::number(mode.length()) + ">" + mode;
|
||||||
|
if(!submode.isEmpty()){
|
||||||
|
t += " <submode:" + QString::number(submode.length()) + ">" + submode;
|
||||||
|
}
|
||||||
t += " <rst_sent:" + QString::number(rptSent.length()) + ">" + rptSent;
|
t += " <rst_sent:" + QString::number(rptSent.length()) + ">" + rptSent;
|
||||||
t += " <rst_rcvd:" + QString::number(rptRcvd.length()) + ">" + rptRcvd;
|
t += " <rst_rcvd:" + QString::number(rptRcvd.length()) + ">" + rptRcvd;
|
||||||
t += " <qso_date:8>" + dateTimeOn.date().toString("yyyyMMdd");
|
t += " <qso_date:8>" + dateTimeOn.date().toString("yyyyMMdd");
|
||||||
|
|||||||
+4
-4
@@ -23,15 +23,15 @@ class ADIF
|
|||||||
public:
|
public:
|
||||||
void init(QString const& filename);
|
void init(QString const& filename);
|
||||||
void load();
|
void load();
|
||||||
void add(QString const& call, QString const& band, QString const& mode, QString const& date);
|
void add(QString const& call, QString const& band, QString const& mode, const QString &submode, QString const& date);
|
||||||
bool match(QString const& call, QString const& band, QString const& mode) const;
|
bool match(QString const& call, QString const& band) const;
|
||||||
QList<QString> getCallList() const;
|
QList<QString> getCallList() const;
|
||||||
int getCount() const;
|
int getCount() const;
|
||||||
|
|
||||||
// open ADIF file and append the QSO details. Return true on success
|
// open ADIF file and append the QSO details. Return true on success
|
||||||
bool addQSOToFile(QByteArray const& ADIF_record);
|
bool addQSOToFile(QByteArray const& ADIF_record);
|
||||||
|
|
||||||
QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent
|
QByteArray QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& submode, QString const& rptSent
|
||||||
, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff
|
, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff
|
||||||
, QString const& band, QString const& comments, QString const& name
|
, QString const& band, QString const& comments, QString const& name
|
||||||
, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid
|
, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid
|
||||||
@@ -41,7 +41,7 @@ class ADIF
|
|||||||
private:
|
private:
|
||||||
struct QSO
|
struct QSO
|
||||||
{
|
{
|
||||||
QString call,band,mode,date;
|
QString call,band,mode,submode,date;
|
||||||
};
|
};
|
||||||
|
|
||||||
QMultiHash<QString, QSO> _data;
|
QMultiHash<QString, QSO> _data;
|
||||||
|
|||||||
+7
-21
@@ -33,19 +33,6 @@ void LogBook::init()
|
|||||||
_log.load();
|
_log.load();
|
||||||
|
|
||||||
_setAlreadyWorkedFromLog();
|
_setAlreadyWorkedFromLog();
|
||||||
|
|
||||||
/*
|
|
||||||
int QSOcount = _log.getCount();
|
|
||||||
int count = _worked.getWorkedCount();
|
|
||||||
qDebug() << QSOcount << "QSOs and" << count << "countries worked in file" << logFilename;
|
|
||||||
*/
|
|
||||||
|
|
||||||
// QString call = "ok1ct";
|
|
||||||
// QString countryName;
|
|
||||||
// bool callWorkedBefore,countryWorkedBefore;
|
|
||||||
// match(/*in*/call, /*out*/ countryName,callWorkedBefore,countryWorkedBefore);
|
|
||||||
// qDebug() << countryName;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -59,11 +46,14 @@ void LogBook::_setAlreadyWorkedFromLog()
|
|||||||
if (countryName.length() > 0)
|
if (countryName.length() > 0)
|
||||||
{
|
{
|
||||||
_worked.setAsWorked(countryName);
|
_worked.setAsWorked(countryName);
|
||||||
//qDebug() << countryName << " worked " << c;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LogBook::hasWorkedBefore(const QString &call, const QString &band){
|
||||||
|
return _log.match(call, band);
|
||||||
|
}
|
||||||
|
|
||||||
void LogBook::match(/*in*/const QString call,
|
void LogBook::match(/*in*/const QString call,
|
||||||
/*out*/ QString &countryName,
|
/*out*/ QString &countryName,
|
||||||
bool &callWorkedBefore,
|
bool &callWorkedBefore,
|
||||||
@@ -71,11 +61,9 @@ void LogBook::match(/*in*/const QString call,
|
|||||||
{
|
{
|
||||||
if (call.length() > 0)
|
if (call.length() > 0)
|
||||||
{
|
{
|
||||||
QString currentMode = "JT9"; // JT65 == JT9 in ADIF::match()
|
|
||||||
QString currentBand = ""; // match any band
|
QString currentBand = ""; // match any band
|
||||||
callWorkedBefore = _log.match(call,currentBand,currentMode);
|
callWorkedBefore = _log.match(call,currentBand);
|
||||||
countryName = _countries.find(call);
|
countryName = _countries.find(call);
|
||||||
// qDebug() << "B" << countryName;
|
|
||||||
|
|
||||||
if (countryName.length() > 0) // country was found
|
if (countryName.length() > 0) // country was found
|
||||||
countryWorkedBefore = _worked.getHasWorked(countryName);
|
countryWorkedBefore = _worked.getHasWorked(countryName);
|
||||||
@@ -85,13 +73,11 @@ void LogBook::match(/*in*/const QString call,
|
|||||||
countryWorkedBefore = false;
|
countryWorkedBefore = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//qDebug() << "Logbook:" << call << ":" << countryName << "Cty B4:" << countryWorkedBefore << "call B4:" << callWorkedBefore;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogBook::addAsWorked(const QString call, const QString band, const QString mode, const QString date)
|
void LogBook::addAsWorked(const QString call, const QString band, const QString mode, const QString submode, const QString date)
|
||||||
{
|
{
|
||||||
//qDebug() << "adding " << call << " as worked";
|
_log.add(call,band,mode,submode,date);
|
||||||
_log.add(call,band,mode,date);
|
|
||||||
QString countryName = _countries.find(call);
|
QString countryName = _countries.find(call);
|
||||||
if (countryName.length() > 0)
|
if (countryName.length() > 0)
|
||||||
_worked.setAsWorked(countryName);
|
_worked.setAsWorked(countryName);
|
||||||
|
|||||||
+2
-1
@@ -20,11 +20,12 @@ class LogBook
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
void init();
|
void init();
|
||||||
|
bool hasWorkedBefore(const QString &call, const QString &band);
|
||||||
void match(/*in*/ const QString call,
|
void match(/*in*/ const QString call,
|
||||||
/*out*/ QString &countryName,
|
/*out*/ QString &countryName,
|
||||||
bool &callWorkedBefore,
|
bool &callWorkedBefore,
|
||||||
bool &countryWorkedBefore) const;
|
bool &countryWorkedBefore) const;
|
||||||
void addAsWorked(const QString call, const QString band, const QString mode, const QString date);
|
void addAsWorked(const QString call, const QString band, const QString mode, const QString submode, const QString date);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CountryDat _countries;
|
CountryDat _countries;
|
||||||
|
|||||||
+12
-8
@@ -95,12 +95,16 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
|
|||||||
|
|
||||||
void LogQSO::accept()
|
void LogQSO::accept()
|
||||||
{
|
{
|
||||||
QString hisCall,hisGrid,mode,rptSent,rptRcvd,dateOn,dateOff,timeOn,timeOff,band,operator_call;
|
QString hisCall,hisGrid,mode,submode,rptSent,rptRcvd,dateOn,dateOff,timeOn,timeOff,band,operator_call;
|
||||||
QString comments,name;
|
QString comments,name;
|
||||||
|
|
||||||
hisCall=ui->call->text();
|
hisCall=ui->call->text().toUpper();
|
||||||
hisGrid=ui->grid->text();
|
hisGrid=ui->grid->text().toUpper();
|
||||||
mode=ui->mode->text();
|
mode = ui->mode->text().toUpper();
|
||||||
|
if(mode == "JS8"){
|
||||||
|
mode="MFSK";
|
||||||
|
submode="JS8";
|
||||||
|
}
|
||||||
rptSent=ui->sent->text();
|
rptSent=ui->sent->text();
|
||||||
rptRcvd=ui->rcvd->text();
|
rptRcvd=ui->rcvd->text();
|
||||||
m_dateTimeOn = ui->start_date_time->dateTime ();
|
m_dateTimeOn = ui->start_date_time->dateTime ();
|
||||||
@@ -115,10 +119,10 @@ void LogQSO::accept()
|
|||||||
//Log this QSO to ADIF file "js8call_log.adi"
|
//Log this QSO to ADIF file "js8call_log.adi"
|
||||||
QString filename = "js8call_log.adi"; // TODO allow user to set
|
QString filename = "js8call_log.adi"; // TODO allow user to set
|
||||||
ADIF adifile;
|
ADIF adifile;
|
||||||
auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("js8call_log.adi");
|
auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (filename);
|
||||||
adifile.init(adifilePath);
|
adifile.init(adifilePath);
|
||||||
|
|
||||||
QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, rptSent, rptRcvd, m_dateTimeOn, m_dateTimeOff, band
|
QByteArray ADIF {adifile.QSOToADIF (hisCall, hisGrid, mode, submode, rptSent, rptRcvd, m_dateTimeOn, m_dateTimeOff, band
|
||||||
, comments, name, strDialFreq, m_myCall, m_myGrid, m_txPower, operator_call)};
|
, comments, name, strDialFreq, m_myCall, m_myGrid, m_txPower, operator_call)};
|
||||||
if (!adifile.addQSOToFile (ADIF))
|
if (!adifile.addQSOToFile (ADIF))
|
||||||
{
|
{
|
||||||
@@ -148,7 +152,7 @@ void LogQSO::accept()
|
|||||||
m_dateTimeOn.time().toString("hh:mm:ss,") +
|
m_dateTimeOn.time().toString("hh:mm:ss,") +
|
||||||
m_dateTimeOff.date().toString("yyyy-MM-dd,") +
|
m_dateTimeOff.date().toString("yyyy-MM-dd,") +
|
||||||
m_dateTimeOff.time().toString("hh:mm:ss,") + hisCall + "," +
|
m_dateTimeOff.time().toString("hh:mm:ss,") + hisCall + "," +
|
||||||
hisGrid + "," + strDialFreq + "," + mode +
|
hisGrid + "," + strDialFreq + "," + (mode == "MFSK" ? "JS8" : mode) +
|
||||||
"," + rptSent + "," + rptRcvd + "," + m_txPower +
|
"," + rptSent + "," + rptRcvd + "," + m_txPower +
|
||||||
"," + comments + "," + name;
|
"," + comments + "," + name;
|
||||||
QTextStream out(&f);
|
QTextStream out(&f);
|
||||||
@@ -157,7 +161,7 @@ void LogQSO::accept()
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Clean up and finish logging
|
//Clean up and finish logging
|
||||||
Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, rptSent, rptRcvd, m_txPower, comments, name,m_dateTimeOn, operator_call, m_myCall, m_myGrid, ADIF);
|
Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, submode, rptSent, rptRcvd, m_txPower, comments, name,m_dateTimeOn, operator_call, m_myCall, m_myGrid, ADIF);
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public slots:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void acceptQSO (QDateTime const& QSO_date_off, QString const& call, QString const& grid
|
void acceptQSO (QDateTime const& QSO_date_off, QString const& call, QString const& grid
|
||||||
, Radio::Frequency dial_freq, QString const& mode
|
, Radio::Frequency dial_freq, QString const& mode, QString const& submode
|
||||||
, QString const& rpt_sent, QString const& rpt_received
|
, QString const& rpt_sent, QString const& rpt_received
|
||||||
, QString const& tx_power, QString const& comments
|
, QString const& tx_power, QString const& comments
|
||||||
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
|
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
|
||||||
|
|||||||
@@ -152,6 +152,9 @@
|
|||||||
<height>16777215</height>
|
<height>16777215</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="readOnly">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
|||||||
+1361
-652
File diff suppressed because it is too large
Load Diff
+65
-25
@@ -130,13 +130,14 @@ public slots:
|
|||||||
void msgAvgDecode2();
|
void msgAvgDecode2();
|
||||||
void fastPick(int x0, int x1, int y);
|
void fastPick(int x0, int x1, int y);
|
||||||
|
|
||||||
|
void playSoundNotification(const QString &path);
|
||||||
bool hasExistingMessageBuffer(int offset, bool drift, int *pPrevOffset);
|
bool hasExistingMessageBuffer(int offset, bool drift, int *pPrevOffset);
|
||||||
void logCallActivity(CallDetail d, bool spot=true);
|
void logCallActivity(CallDetail d, bool spot=true);
|
||||||
QString lookupCallInCompoundCache(QString const &call);
|
QString lookupCallInCompoundCache(QString const &call);
|
||||||
void cacheActivity(QString key);
|
void cacheActivity(QString key);
|
||||||
void restoreActivity(QString key);
|
void restoreActivity(QString key);
|
||||||
void clearActivity();
|
void clearActivity();
|
||||||
void createAllcallTableRow(QTableWidget *table, bool selected);
|
void createAllcallTableRows(QTableWidget *table, const QString &selectedCall);
|
||||||
void displayTextForFreq(QString text, int freq, QDateTime date, bool isTx, bool isNewLine, bool isLast);
|
void displayTextForFreq(QString text, int freq, QDateTime date, bool isTx, bool isNewLine, bool isLast);
|
||||||
void writeNoticeTextToUI(QDateTime date, QString text);
|
void writeNoticeTextToUI(QDateTime date, QString text);
|
||||||
int writeMessageTextToUI(QDateTime date, QString text, int freq, bool bold, int block=-1);
|
int writeMessageTextToUI(QDateTime date, QString text, int freq, bool bold, int block=-1);
|
||||||
@@ -144,17 +145,18 @@ public slots:
|
|||||||
void prependMessageText(QString text);
|
void prependMessageText(QString text);
|
||||||
void addMessageText(QString text, bool clear=false, bool selectFirstPlaceholder=false);
|
void addMessageText(QString text, bool clear=false, bool selectFirstPlaceholder=false);
|
||||||
void enqueueMessage(int priority, QString message, int freq, Callback c);
|
void enqueueMessage(int priority, QString message, int freq, Callback c);
|
||||||
void enqueueBeacon(QString message);
|
void enqueueHeartbeat(QString message);
|
||||||
void resetMessage();
|
void resetMessage();
|
||||||
void resetMessageUI();
|
void resetMessageUI();
|
||||||
void restoreMessage();
|
void restoreMessage();
|
||||||
void initializeDummyData();
|
void initializeDummyData();
|
||||||
bool ensureCallsignSet(bool alert=true);
|
bool ensureCallsignSet(bool alert=true);
|
||||||
bool ensureSelcalCallsignSelected(bool alert=true);
|
bool ensureSelcalCallsignSelected(bool alert=true);
|
||||||
|
bool ensureKeyNotStuck(QString const& text);
|
||||||
void createMessage(QString const& text);
|
void createMessage(QString const& text);
|
||||||
void createMessageTransmitQueue(QString const& text);
|
void createMessageTransmitQueue(QString const& text);
|
||||||
void resetMessageTransmitQueue();
|
void resetMessageTransmitQueue();
|
||||||
QString popMessageFrame();
|
QPair<QString, int> popMessageFrame();
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent (QKeyEvent *) override;
|
void keyPressEvent (QKeyEvent *) override;
|
||||||
void closeEvent(QCloseEvent *) override;
|
void closeEvent(QCloseEvent *) override;
|
||||||
@@ -169,7 +171,14 @@ private slots:
|
|||||||
void on_tx4_editingFinished();
|
void on_tx4_editingFinished();
|
||||||
void on_tx5_currentTextChanged (QString const&);
|
void on_tx5_currentTextChanged (QString const&);
|
||||||
void on_tx6_editingFinished();
|
void on_tx6_editingFinished();
|
||||||
|
void on_menuControl_aboutToShow();
|
||||||
|
void on_actionEnable_Spotting_toggled(bool checked);
|
||||||
|
void on_actionEnable_Active_toggled(bool checked);
|
||||||
|
void on_actionEnable_Auto_Reply_toggled(bool checked);
|
||||||
|
void on_actionEnable_Selcall_toggled(bool checked);
|
||||||
void on_menuWindow_aboutToShow();
|
void on_menuWindow_aboutToShow();
|
||||||
|
void on_actionShow_Fullscreen_triggered(bool checked);
|
||||||
|
void on_actionShow_Frequency_Clock_triggered(bool checked);
|
||||||
void on_actionShow_Band_Activity_triggered(bool checked);
|
void on_actionShow_Band_Activity_triggered(bool checked);
|
||||||
void on_actionShow_Call_Activity_triggered(bool checked);
|
void on_actionShow_Call_Activity_triggered(bool checked);
|
||||||
void on_actionShow_Waterfall_triggered(bool checked);
|
void on_actionShow_Waterfall_triggered(bool checked);
|
||||||
@@ -184,6 +193,7 @@ private slots:
|
|||||||
void on_actionAbout_triggered();
|
void on_actionAbout_triggered();
|
||||||
void on_autoButton_clicked (bool);
|
void on_autoButton_clicked (bool);
|
||||||
void on_labDialFreq_clicked();
|
void on_labDialFreq_clicked();
|
||||||
|
void resetPushButtonToggleText(QPushButton *btn);
|
||||||
void on_monitorTxButton_clicked();
|
void on_monitorTxButton_clicked();
|
||||||
void on_stopTxButton_clicked();
|
void on_stopTxButton_clicked();
|
||||||
void on_stopButton_clicked();
|
void on_stopButton_clicked();
|
||||||
@@ -209,8 +219,6 @@ private slots:
|
|||||||
void decode();
|
void decode();
|
||||||
void decodeBusy(bool b);
|
void decodeBusy(bool b);
|
||||||
void on_EraseButton_clicked();
|
void on_EraseButton_clicked();
|
||||||
void band_activity_cleared ();
|
|
||||||
void rx_frequency_activity_cleared ();
|
|
||||||
void set_dateTimeQSO(int m_ntx);
|
void set_dateTimeQSO(int m_ntx);
|
||||||
void set_ntx(int n);
|
void set_ntx(int n);
|
||||||
void on_txrb1_toggled(bool status);
|
void on_txrb1_toggled(bool status);
|
||||||
@@ -246,6 +254,7 @@ private slots:
|
|||||||
void on_actionSave_decoded_triggered();
|
void on_actionSave_decoded_triggered();
|
||||||
void on_actionQuickDecode_toggled (bool);
|
void on_actionQuickDecode_toggled (bool);
|
||||||
void on_actionMediumDecode_toggled (bool);
|
void on_actionMediumDecode_toggled (bool);
|
||||||
|
void on_actionDeepDecode_toggled (bool);
|
||||||
void on_actionDeepestDecode_toggled (bool);
|
void on_actionDeepestDecode_toggled (bool);
|
||||||
void bumpFqso(int n);
|
void bumpFqso(int n);
|
||||||
void on_actionErase_ALL_TXT_triggered();
|
void on_actionErase_ALL_TXT_triggered();
|
||||||
@@ -265,12 +274,21 @@ private slots:
|
|||||||
void on_rbGenMsg_clicked(bool checked);
|
void on_rbGenMsg_clicked(bool checked);
|
||||||
void on_rbFreeText_clicked(bool checked);
|
void on_rbFreeText_clicked(bool checked);
|
||||||
void on_clearAction_triggered(QObject * sender);
|
void on_clearAction_triggered(QObject * sender);
|
||||||
|
void buildHeartbeatMenu(QMenu *menu);
|
||||||
|
void buildCQMenu(QMenu *menu);
|
||||||
|
void buildRepeatMenu(QMenu *menu, QPushButton * button, int * interval);
|
||||||
|
void sendHeartbeat();
|
||||||
|
void on_hbMacroButton_toggled(bool checked);
|
||||||
|
void on_hbMacroButton_clicked();
|
||||||
|
void sendCQ(bool repeat=false);
|
||||||
|
void on_cqMacroButton_toggled(bool checked);
|
||||||
void on_cqMacroButton_clicked();
|
void on_cqMacroButton_clicked();
|
||||||
void on_replyMacroButton_clicked();
|
void on_replyMacroButton_clicked();
|
||||||
|
void on_snrMacroButton_clicked();
|
||||||
void on_qthMacroButton_clicked();
|
void on_qthMacroButton_clicked();
|
||||||
void on_qtcMacroButton_clicked();
|
void on_qtcMacroButton_clicked();
|
||||||
void setShowColumn(QString tableKey, QString columnKey, bool value);
|
void setShowColumn(QString tableKey, QString columnKey, bool value);
|
||||||
bool showColumn(QString tableKey, QString columnKey);
|
bool showColumn(QString tableKey, QString columnKey, bool default_=true);
|
||||||
void buildShowColumnsMenu(QMenu *menu, QString tableKey);
|
void buildShowColumnsMenu(QMenu *menu, QString tableKey);
|
||||||
void setSortBy(QString key, QString value);
|
void setSortBy(QString key, QString value);
|
||||||
QString getSortBy(QString key, QString defaultValue);
|
QString getSortBy(QString key, QString defaultValue);
|
||||||
@@ -278,6 +296,8 @@ private slots:
|
|||||||
void buildBandActivitySortByMenu(QMenu * menu);
|
void buildBandActivitySortByMenu(QMenu * menu);
|
||||||
void buildCallActivitySortByMenu(QMenu * menu);
|
void buildCallActivitySortByMenu(QMenu * menu);
|
||||||
void buildQueryMenu(QMenu *, QString callsign);
|
void buildQueryMenu(QMenu *, QString callsign);
|
||||||
|
QMap<QString, QString> buildMacroValues();
|
||||||
|
QString replaceMacros(QString const &text, QMap<QString, QString> values, bool prune);
|
||||||
void buildSavedMessagesMenu(QMenu *menu);
|
void buildSavedMessagesMenu(QMenu *menu);
|
||||||
void buildRelayMenu(QMenu *menu);
|
void buildRelayMenu(QMenu *menu);
|
||||||
QAction* buildRelayAction(QString call);
|
QAction* buildRelayAction(QString call);
|
||||||
@@ -295,15 +315,12 @@ private slots:
|
|||||||
void on_nextFreeTextMsg_currentTextChanged (QString const&);
|
void on_nextFreeTextMsg_currentTextChanged (QString const&);
|
||||||
void on_extFreeTextMsgEdit_currentTextChanged (QString const&);
|
void on_extFreeTextMsgEdit_currentTextChanged (QString const&);
|
||||||
int currentFreqOffset();
|
int currentFreqOffset();
|
||||||
QStringList buildMessageFrames(QString const& text);
|
QList<QPair<QString, int>> buildMessageFrames(QString const& text);
|
||||||
bool prepareNextMessageFrame();
|
bool prepareNextMessageFrame();
|
||||||
bool isFreqOffsetFree(int f, int bw);
|
bool isFreqOffsetFree(int f, int bw);
|
||||||
int findFreeFreqOffset(int fmin, int fmax, int bw);
|
int findFreeFreqOffset(int fmin, int fmax, int bw);
|
||||||
void scheduleBeacon(bool first=false);
|
void checkRepeat();
|
||||||
void pauseBeacon();
|
QString calculateDistance(QString const& grid, int *pDistance=nullptr, int *pAzimuth=nullptr);
|
||||||
void checkBeacon();
|
|
||||||
void prepareBeacon();
|
|
||||||
QString calculateDistance(QString const& grid, int *pDistance=nullptr);
|
|
||||||
void on_driftSpinBox_valueChanged(int n);
|
void on_driftSpinBox_valueChanged(int n);
|
||||||
void on_driftSyncButton_clicked();
|
void on_driftSyncButton_clicked();
|
||||||
void on_driftSyncEndButton_clicked();
|
void on_driftSyncEndButton_clicked();
|
||||||
@@ -314,10 +331,8 @@ private slots:
|
|||||||
void on_tuneButton_clicked (bool);
|
void on_tuneButton_clicked (bool);
|
||||||
void on_pbR2T_clicked();
|
void on_pbR2T_clicked();
|
||||||
void on_pbT2R_clicked();
|
void on_pbT2R_clicked();
|
||||||
void on_beaconButton_clicked();
|
|
||||||
void on_selcalButton_clicked();
|
|
||||||
void acceptQSO (QDateTime const&, QString const& call, QString const& grid
|
void acceptQSO (QDateTime const&, QString const& call, QString const& grid
|
||||||
, Frequency dial_freq, QString const& mode
|
, Frequency dial_freq, QString const& mode, QString const& submode
|
||||||
, QString const& rpt_sent, QString const& rpt_received
|
, QString const& rpt_sent, QString const& rpt_received
|
||||||
, QString const& tx_power, QString const& comments
|
, QString const& tx_power, QString const& comments
|
||||||
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
|
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
|
||||||
@@ -338,6 +353,14 @@ private slots:
|
|||||||
void stop_tuning ();
|
void stop_tuning ();
|
||||||
void stopTuneATU();
|
void stopTuneATU();
|
||||||
void auto_tx_mode(bool);
|
void auto_tx_mode(bool);
|
||||||
|
void on_autoReplyButton_toggled(bool checked);
|
||||||
|
void on_monitorButton_toggled(bool checked);
|
||||||
|
void on_monitorTxButton_toggled(bool checked);
|
||||||
|
void on_selcalButton_toggled(bool checked);
|
||||||
|
void on_tuneButton_toggled(bool checked);
|
||||||
|
void on_spotButton_toggled(bool checked);
|
||||||
|
void on_activeButton_toggled(bool checked);
|
||||||
|
|
||||||
void on_actionMessage_averaging_triggered();
|
void on_actionMessage_averaging_triggered();
|
||||||
void on_actionFox_Log_triggered();
|
void on_actionFox_Log_triggered();
|
||||||
void on_actionInclude_averaging_toggled (bool);
|
void on_actionInclude_averaging_toggled (bool);
|
||||||
@@ -411,7 +434,7 @@ private:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void astroUpdate ();
|
void astroUpdate ();
|
||||||
void writeAllTxt(QString message);
|
void writeAllTxt(QString message, int bits);
|
||||||
void hideMenus(bool b);
|
void hideMenus(bool b);
|
||||||
|
|
||||||
NetworkAccessManager m_network_manager;
|
NetworkAccessManager m_network_manager;
|
||||||
@@ -549,6 +572,7 @@ private:
|
|||||||
bool m_sentFirst73;
|
bool m_sentFirst73;
|
||||||
int m_currentMessageType;
|
int m_currentMessageType;
|
||||||
QString m_currentMessage;
|
QString m_currentMessage;
|
||||||
|
int m_currentMessageBits;
|
||||||
int m_lastMessageType;
|
int m_lastMessageType;
|
||||||
QString m_lastMessageSent;
|
QString m_lastMessageSent;
|
||||||
bool m_bShMsgs;
|
bool m_bShMsgs;
|
||||||
@@ -643,7 +667,7 @@ private:
|
|||||||
QTimer minuteTimer;
|
QTimer minuteTimer;
|
||||||
QTimer splashTimer;
|
QTimer splashTimer;
|
||||||
QTimer p1Timer;
|
QTimer p1Timer;
|
||||||
QTimer beaconTimer;
|
QTimer repeatTimer;
|
||||||
|
|
||||||
QString m_path;
|
QString m_path;
|
||||||
QString m_baseCall;
|
QString m_baseCall;
|
||||||
@@ -684,6 +708,7 @@ private:
|
|||||||
QDateTime utcTimestamp;
|
QDateTime utcTimestamp;
|
||||||
int snr;
|
int snr;
|
||||||
int bits;
|
int bits;
|
||||||
|
float tdrift;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CommandDetail
|
struct CommandDetail
|
||||||
@@ -700,6 +725,7 @@ private:
|
|||||||
QString grid;
|
QString grid;
|
||||||
QString text;
|
QString text;
|
||||||
QString extra;
|
QString extra;
|
||||||
|
float tdrift;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ActivityDetail
|
struct ActivityDetail
|
||||||
@@ -715,6 +741,7 @@ private:
|
|||||||
QDateTime utcTimestamp;
|
QDateTime utcTimestamp;
|
||||||
int snr;
|
int snr;
|
||||||
bool shouldDisplay;
|
bool shouldDisplay;
|
||||||
|
float tdrift;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MessageBuffer {
|
struct MessageBuffer {
|
||||||
@@ -734,7 +761,8 @@ private:
|
|||||||
QString m_txTextDirtyLastSelectedCall;
|
QString m_txTextDirtyLastSelectedCall;
|
||||||
QString m_lastTxMessage;
|
QString m_lastTxMessage;
|
||||||
QDateTime m_lastTxTime;
|
QDateTime m_lastTxTime;
|
||||||
|
int m_timeDeltaMsMMA;
|
||||||
|
int m_timeDeltaMsMMA_N;
|
||||||
|
|
||||||
enum Priority {
|
enum Priority {
|
||||||
PriorityLow = 10,
|
PriorityLow = 10,
|
||||||
@@ -765,7 +793,7 @@ private:
|
|||||||
QMap<QString, QVariant> m_showColumnsCache; // table column:key -> show boolean
|
QMap<QString, QVariant> m_showColumnsCache; // table column:key -> show boolean
|
||||||
QMap<QString, QVariant> m_sortCache; // table key -> sort by
|
QMap<QString, QVariant> m_sortCache; // table key -> sort by
|
||||||
QPriorityQueue<PrioritizedMessage> m_txMessageQueue; // messages to be sent
|
QPriorityQueue<PrioritizedMessage> m_txMessageQueue; // messages to be sent
|
||||||
QQueue<QString> m_txFrameQueue; // frames to be sent
|
QQueue<QPair<QString, int>> m_txFrameQueue; // frames to be sent
|
||||||
QQueue<ActivityDetail> m_rxActivityQueue; // all rx activity queue
|
QQueue<ActivityDetail> m_rxActivityQueue; // all rx activity queue
|
||||||
QQueue<CommandDetail> m_rxCommandQueue; // command queue for processing commands
|
QQueue<CommandDetail> m_rxCommandQueue; // command queue for processing commands
|
||||||
QQueue<CallDetail> m_rxCallQueue; // call detail queue for spots to pskreporter
|
QQueue<CallDetail> m_rxCallQueue; // call detail queue for spots to pskreporter
|
||||||
@@ -778,14 +806,14 @@ private:
|
|||||||
QMap<int, QList<ActivityDetail>> m_bandActivity; // freq -> [(text, last timestamp), ...]
|
QMap<int, QList<ActivityDetail>> m_bandActivity; // freq -> [(text, last timestamp), ...]
|
||||||
QMap<int, MessageBuffer> m_messageBuffer; // freq -> (cmd, [frames, ...])
|
QMap<int, MessageBuffer> m_messageBuffer; // freq -> (cmd, [frames, ...])
|
||||||
QMap<QString, CallDetail> m_callActivity; // call -> (last freq, last timestamp)
|
QMap<QString, CallDetail> m_callActivity; // call -> (last freq, last timestamp)
|
||||||
QQueue<QString> m_txBeaconQueue; // beacon frames to be sent
|
QQueue<QString> m_txHeartbeatQueue; // ping frames to be sent
|
||||||
QMap<QString, QDateTime> m_aprsCallCache;
|
QMap<QString, QDateTime> m_aprsCallCache;
|
||||||
|
|
||||||
QMap<QString, QMap<QString, CallDetail>> m_callActivityCache; // band -> call activity
|
QMap<QString, QMap<QString, CallDetail>> m_callActivityCache; // band -> call activity
|
||||||
QMap<QString, QMap<int, QList<ActivityDetail>>> m_bandActivityCache; // band -> band activity
|
QMap<QString, QMap<int, QList<ActivityDetail>>> m_bandActivityCache; // band -> band activity
|
||||||
QMap<QString, QString> m_rxTextCache; // band -> rx text
|
QMap<QString, QString> m_rxTextCache; // band -> rx text
|
||||||
|
|
||||||
QSet<QString> m_callSeenBeacon; // call
|
QSet<QString> m_callSeenHeartbeat; // call
|
||||||
int m_previousFreq;
|
int m_previousFreq;
|
||||||
bool m_shouldRestoreFreq;
|
bool m_shouldRestoreFreq;
|
||||||
bool m_bandHopped;
|
bool m_bandHopped;
|
||||||
@@ -809,9 +837,11 @@ private:
|
|||||||
QQueue<QString> m_foxQSOinProgress; //QSOs in progress: Fox has sent a report
|
QQueue<QString> m_foxQSOinProgress; //QSOs in progress: Fox has sent a report
|
||||||
QQueue<qint64> m_foxRateQueue;
|
QQueue<qint64> m_foxRateQueue;
|
||||||
|
|
||||||
bool m_nextBeaconQueued = false;
|
bool m_hbHidden;
|
||||||
bool m_nextBeaconPaused = false;
|
int m_hbInterval;
|
||||||
QDateTime m_nextBeacon;
|
int m_cqInterval;
|
||||||
|
QDateTime m_nextHeartbeat;
|
||||||
|
QDateTime m_nextCQ;
|
||||||
QDateTime m_dateTimeQSOOn;
|
QDateTime m_dateTimeQSOOn;
|
||||||
QDateTime m_dateTimeLastTX;
|
QDateTime m_dateTimeLastTX;
|
||||||
|
|
||||||
@@ -828,6 +858,7 @@ private:
|
|||||||
bool m_tx_when_ready;
|
bool m_tx_when_ready;
|
||||||
bool m_transmitting;
|
bool m_transmitting;
|
||||||
bool m_tune;
|
bool m_tune;
|
||||||
|
bool m_deadAirTone;
|
||||||
bool m_tx_watchdog; // true when watchdog triggered
|
bool m_tx_watchdog; // true when watchdog triggered
|
||||||
bool m_block_pwr_tooltip;
|
bool m_block_pwr_tooltip;
|
||||||
bool m_PwrBandSetOK;
|
bool m_PwrBandSetOK;
|
||||||
@@ -837,7 +868,6 @@ private:
|
|||||||
double m_toneSpacing;
|
double m_toneSpacing;
|
||||||
int m_firstDecode;
|
int m_firstDecode;
|
||||||
QProgressDialog m_optimizingProgress;
|
QProgressDialog m_optimizingProgress;
|
||||||
QTimer m_heartbeat;
|
|
||||||
MessageClient * m_messageClient;
|
MessageClient * m_messageClient;
|
||||||
PSK_Reporter *psk_Reporter;
|
PSK_Reporter *psk_Reporter;
|
||||||
APRSISClient * m_aprsClient;
|
APRSISClient * m_aprsClient;
|
||||||
@@ -876,6 +906,7 @@ private:
|
|||||||
void postDecode (bool is_new, QString const& message);
|
void postDecode (bool is_new, QString const& message);
|
||||||
void displayTransmit();
|
void displayTransmit();
|
||||||
void updateButtonDisplay();
|
void updateButtonDisplay();
|
||||||
|
void updateRepeatButtonDisplay();
|
||||||
void updateTextDisplay();
|
void updateTextDisplay();
|
||||||
void updateFrameCountEstimate(int count);
|
void updateFrameCountEstimate(int count);
|
||||||
void updateTextStatsDisplay(QString text, int count);
|
void updateTextStatsDisplay(QString text, int count);
|
||||||
@@ -890,6 +921,8 @@ private:
|
|||||||
void markOffsetDirected(int offset, bool isAllCall);
|
void markOffsetDirected(int offset, bool isAllCall);
|
||||||
void clearOffsetDirected(int offset);
|
void clearOffsetDirected(int offset);
|
||||||
void processActivity(bool force=false);
|
void processActivity(bool force=false);
|
||||||
|
void observeTimeDeltaForAverage(float delta);
|
||||||
|
void resetTimeDeltaAverage();
|
||||||
void processRxActivity();
|
void processRxActivity();
|
||||||
void processCompoundActivity();
|
void processCompoundActivity();
|
||||||
void processBufferedActivity();
|
void processBufferedActivity();
|
||||||
@@ -922,6 +955,10 @@ private:
|
|||||||
, QString const& his_call
|
, QString const& his_call
|
||||||
, QString const& his_grid) const;
|
, QString const& his_grid) const;
|
||||||
void read_wav_file (QString const& fname);
|
void read_wav_file (QString const& fname);
|
||||||
|
QDateTime nextTransmitCycle();
|
||||||
|
void resetAutomaticIntervalTransmissions(bool stopCQ, bool stopHB);
|
||||||
|
void resetCQTimer(bool stop);
|
||||||
|
void resetHeartbeatTimer(bool stop);
|
||||||
void decodeDone ();
|
void decodeDone ();
|
||||||
void subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus);
|
void subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus);
|
||||||
void subProcessError (QProcess *, QProcess::ProcessError);
|
void subProcessError (QProcess *, QProcess::ProcessError);
|
||||||
@@ -932,6 +969,9 @@ private:
|
|||||||
void add_child_to_event_filter (QObject *);
|
void add_child_to_event_filter (QObject *);
|
||||||
void remove_child_from_event_filter (QObject *);
|
void remove_child_from_event_filter (QObject *);
|
||||||
void setup_status_bar (bool vhf);
|
void setup_status_bar (bool vhf);
|
||||||
|
|
||||||
|
void resetIdleTimer();
|
||||||
|
void incrementIdleTimer();
|
||||||
void tx_watchdog (bool triggered);
|
void tx_watchdog (bool triggered);
|
||||||
qint64 nWidgets(QString t);
|
qint64 nWidgets(QString t);
|
||||||
void displayWidgets(qint64 n);
|
void displayWidgets(qint64 n);
|
||||||
|
|||||||
+802
-717
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -578,7 +578,7 @@ void CPlotter::DrawOverlay() //DrawOverlay()
|
|||||||
x1=XfromFreq(500);
|
x1=XfromFreq(500);
|
||||||
x2=XfromFreq(1000);
|
x2=XfromFreq(1000);
|
||||||
if(x1<=m_w and x2>0) {
|
if(x1<=m_w and x2>0) {
|
||||||
painter0.setPen(penBlue); //Mark beacon range
|
painter0.setPen(penBlue); //Mark ping range
|
||||||
painter0.drawLine(x1+1,26,x2-2,26);
|
painter0.drawLine(x1+1,26,x2-2,26);
|
||||||
painter0.drawLine(x1+1,28,x2-2,28);
|
painter0.drawLine(x1+1,28,x2-2,28);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -33,6 +33,8 @@ QString version (bool include_patch)
|
|||||||
|
|
||||||
QString program_title (QString const& revision)
|
QString program_title (QString const& revision)
|
||||||
{
|
{
|
||||||
QString id {"JS8Call de KN4CRD (v%1)"};
|
QString id {"%1 DE KN4CRD (v%2)"};
|
||||||
return id.arg(QCoreApplication::applicationVersion ());
|
id = id.arg(QCoreApplication::applicationName());
|
||||||
|
id = id.arg(QCoreApplication::applicationVersion ());
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|||||||
+386
-189
@@ -27,37 +27,57 @@
|
|||||||
|
|
||||||
#include "varicode.h"
|
#include "varicode.h"
|
||||||
#include "jsc.h"
|
#include "jsc.h"
|
||||||
|
#include "decodedtext.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
const int nalphabet = 41;
|
const int nalphabet = 41;
|
||||||
QString alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"}; // alphabet to encode _into_ for FT8 freetext transmission
|
QString alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"}; // alphabet to encode _into_ for FT8 freetext transmission
|
||||||
QString alphabet72 = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+/?."};
|
QString alphabet72 = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+/?."};
|
||||||
QString grid_pattern = {R"((?<grid>[A-X]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*)+)"};
|
QString grid_pattern = {R"((?<grid>[A-X]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*)+)"};
|
||||||
QString orig_compound_callsign_pattern = {R"((?<callsign>(\d|[A-Z])+\/?((\d|[A-Z]){2,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"};
|
QString orig_compound_callsign_pattern = {R"((?<callsign>(\d|[A-Z])+\/?((\d|[A-Z]){2,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"};
|
||||||
QString compound_callsign_pattern = {R"((?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[A-Z0-9]{1,4})?)\b)"};
|
QString base_callsign_pattern = {R"((?<callsign>\b(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)\b))"};
|
||||||
|
//QString compound_callsign_pattern = {R"((?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[A-Z0-9]{1,4})?)\b)"};
|
||||||
|
QString compound_callsign_pattern = {R"((?<callsign>(?:[@]?|\b)(?<extended>[A-Z0-9\/@][A-Z0-9\/]{0,2}[\/]?[A-Z0-9\/]{0,3}[\/]?[A-Z0-9\/]{0,3})\b))"};
|
||||||
QString pack_callsign_pattern = {R"(([0-9A-Z ])([0-9A-Z])([0-9])([A-Z ])([A-Z ])([A-Z ]))"};
|
QString pack_callsign_pattern = {R"(([0-9A-Z ])([0-9A-Z])([0-9])([A-Z ])([A-Z ])([A-Z ]))"};
|
||||||
QString alphanumeric = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ "}; // callsign and grid alphabet
|
QString alphanumeric = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ /@"}; // callsign and grid alphabet
|
||||||
|
|
||||||
QMap<QString, int> directed_cmds = {
|
QMap<QString, int> directed_cmds = {
|
||||||
// any changes here need to be made also in the directed regular xpression for parsing
|
// any changes here need to be made also in the directed regular xpression for parsing
|
||||||
|
// ?*^&@
|
||||||
|
|
||||||
{"?", 0 }, // query snr
|
{" SNR?", 0 }, // query snr
|
||||||
{"@", 1 }, // query qth
|
{"?", 0 }, // compat
|
||||||
{"&", 2 }, // query station message
|
|
||||||
{"$", 3 }, // query station(s) heard
|
|
||||||
{"^", 4 }, // query grid
|
|
||||||
{">", 5 }, // relay message
|
|
||||||
{"*", 6 }, // query idle message
|
|
||||||
//{"!", 7 }, // alert message
|
|
||||||
{"#", 8 }, // all or nothing message
|
|
||||||
|
|
||||||
// {"=", 9 }, // unused
|
{" QTH?", 1 }, // query qth
|
||||||
|
{"@", 1 }, // compat
|
||||||
|
|
||||||
{" ACTIVE", 10 }, // i have been active in the past 10 minutes
|
{" QTC?", 2 }, // query station message
|
||||||
{" IDLE", 11 }, // i have not been active in the past 10 minutes
|
{"&", 2 }, // compat
|
||||||
|
|
||||||
{" BEACON", -1 }, // this is my beacon (unused except for faux processing of beacons as directed commands)
|
//{"$", 3 }, // unused
|
||||||
{" BEACON ACK", 12 }, // i received your beacon at this snr
|
|
||||||
{" BEACON REQ", 13 }, // can you transmit a beacon to callsign?
|
{" GRID?", 4 }, // query grid
|
||||||
|
{"^", 4 }, // compat
|
||||||
|
|
||||||
|
{">", 5 }, // relay message
|
||||||
|
|
||||||
|
{" STATUS?", 6 }, // query idle message
|
||||||
|
{"*", 6 }, // compat
|
||||||
|
|
||||||
|
//{"!", 7 }, // unused
|
||||||
|
|
||||||
|
{"#", 8 }, // all or nothing message
|
||||||
|
|
||||||
|
{" TU", 9 }, // thank you
|
||||||
|
|
||||||
|
{" ACTIVE", 10 }, // i am active
|
||||||
|
{" IDLE", 11 }, // i am idle
|
||||||
|
|
||||||
|
{" HB", -1 }, // this is my heartbeat (unused except for faux processing of HBs as directed commands)
|
||||||
|
{" HB ACK", 12 }, // (unused, but a compatibility display)
|
||||||
|
|
||||||
|
{" QUERY", 13 }, // can you transmit a ping to callsign?
|
||||||
|
|
||||||
{" APRS:", 14 }, // send an aprs packet
|
{" APRS:", 14 }, // send an aprs packet
|
||||||
|
|
||||||
@@ -67,7 +87,7 @@ QMap<QString, int> directed_cmds = {
|
|||||||
|
|
||||||
{" FB", 18 }, // fine business
|
{" FB", 18 }, // fine business
|
||||||
{" HW CPY?", 19 }, // how do you copy?
|
{" HW CPY?", 19 }, // how do you copy?
|
||||||
{" HEARING", 20 }, // i am hearing the following stations
|
{" SK", 20 }, // end of contact
|
||||||
{" RR", 21 }, // roger roger
|
{" RR", 21 }, // roger roger
|
||||||
{" QSL?", 22 }, // do you copy?
|
{" QSL?", 22 }, // do you copy?
|
||||||
{" QSL", 23 }, // i copy
|
{" QSL", 23 }, // i copy
|
||||||
@@ -81,32 +101,32 @@ QMap<QString, int> directed_cmds = {
|
|||||||
{" ", 31 }, // send freetext
|
{" ", 31 }, // send freetext
|
||||||
};
|
};
|
||||||
|
|
||||||
QSet<int> allowed_cmds = {-1, 0, 1, 2, 3, 4, 5, 6, /*7,*/ 8, /*9,*/ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
|
QSet<int> allowed_cmds = {-1, 0, 1, 2, 3, 4, 5, 6, /*7,*/ 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
|
||||||
|
|
||||||
QSet<int> buffered_cmds = {3, 5, /*6,*/ /*7,*/ 8, 13, 14, 15};
|
QSet<int> buffered_cmds = {3, 5, /*6,*/ /*7,*/ 8, 13, 14, 15};
|
||||||
|
|
||||||
QSet<int> snr_cmds = {12, 25};
|
QSet<int> snr_cmds = {25, 29};
|
||||||
|
|
||||||
QMap<int, int> checksum_cmds = {
|
QMap<int, int> checksum_cmds = {
|
||||||
{ 5, 16 },
|
{ 5, 16 },
|
||||||
{ 8, 32 },
|
{ 8, 16 },
|
||||||
{ 13, 16 },
|
{ 13, 16 },
|
||||||
{ 14, 16 },
|
{ 14, 16 },
|
||||||
{ 15, 0 }
|
{ 15, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
QString callsign_pattern = QString("(?<callsign>[A-Z0-9/]+)");
|
QString callsign_pattern = QString("(?<callsign>[@]?[A-Z0-9/]+)");
|
||||||
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:BEACON (ACK|REQ)|AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|QRZ[?]|(?:(?:ACK|73|YES|NO|SNR|QSL|RR|HEARING|FB|QTH|QTC|GRID|ACTIVE|IDLE)(?=[ ]|$))|[?@&$%#^>* ]))?");
|
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|QRZ[?]|SNR[?]|QTC[?]|QTH[?]|GRID[?]|STATUS[?]|(?:(?:QUERY|ACK|73|YES|NO|SNR|QSL|RR|SK|FB|QTH|QTC|GRID|ACTIVE|IDLE|TU)(?=[ ]|$))|[?*^&@#> ]))?");
|
||||||
QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?");
|
QString optional_grid_pattern = QString("(?<grid>\\s?[A-R]{2}[0-9]{2})?");
|
||||||
QString optional_extended_grid_pattern = QString("^(?<grid>\\s?(?:[A-R]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*))?");
|
QString optional_extended_grid_pattern = QString("^(?<grid>\\s?(?:[A-R]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*))?");
|
||||||
QString optional_num_pattern = QString("(?<num>(?<=SNR|BEACON ACK)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
|
QString optional_num_pattern = QString("(?<num>(?<=SNR|ACK)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
|
||||||
|
|
||||||
QRegularExpression directed_re("^" +
|
QRegularExpression directed_re("^" +
|
||||||
callsign_pattern +
|
callsign_pattern +
|
||||||
optional_cmd_pattern +
|
optional_cmd_pattern +
|
||||||
optional_num_pattern);
|
optional_num_pattern);
|
||||||
|
|
||||||
QRegularExpression beacon_re(R"(^\s*(?<type>CQCQCQ|CQ QRPP?|CQ DX|CQ TEST|CQ( CQ){0,2}|BEACON)(?:\s(?<grid>[A-R]{2}[0-9]{2}))?\b)");
|
QRegularExpression heartbeat_re(R"(^\s*(?<type>CQCQCQ|CQ QRPP?|CQ DX|CQ TEST|CQ( CQ){0,2}|HB (ACTIVE|IDLE))(?:\s(?<grid>[A-R]{2}[0-9]{2}))?\b)");
|
||||||
|
|
||||||
QRegularExpression compound_re("^\\s*[`]" +
|
QRegularExpression compound_re("^\\s*[`]" +
|
||||||
callsign_pattern +
|
callsign_pattern +
|
||||||
@@ -174,8 +194,7 @@ quint16 nmaxgrid = (1<<15)-1;
|
|||||||
|
|
||||||
QMap<QString, quint32> basecalls = {
|
QMap<QString, quint32> basecalls = {
|
||||||
{ "<....>", nbasecall + 1 }, // incomplete callsign
|
{ "<....>", nbasecall + 1 }, // incomplete callsign
|
||||||
{ "ALLCALL", nbasecall + 2 },
|
{ "@ALLCALL", nbasecall + 2 }, // ALLCALL group
|
||||||
{ "GROUPCALL", nbasecall + 3 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QMap<quint32, QString> cqs = {
|
QMap<quint32, QString> cqs = {
|
||||||
@@ -189,6 +208,12 @@ QMap<quint32, QString> cqs = {
|
|||||||
{ 7, "CQ CQ CQ"},
|
{ 7, "CQ CQ CQ"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QMap<quint32, QString> hbs = {
|
||||||
|
{ 0, "HB ACTIVE" },
|
||||||
|
{ 1, "HB IDLE" },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
QMap<int, int> dbm2mw = {
|
QMap<int, int> dbm2mw = {
|
||||||
{0 , 1}, // 1mW
|
{0 , 1}, // 1mW
|
||||||
{3 , 2}, // 2mW
|
{3 , 2}, // 2mW
|
||||||
@@ -275,6 +300,13 @@ QString Varicode::cqString(int number){
|
|||||||
return cqs[number];
|
return cqs[number];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Varicode::hbString(int number){
|
||||||
|
if(!hbs.contains(number)){
|
||||||
|
return QString{};
|
||||||
|
}
|
||||||
|
return hbs[number];
|
||||||
|
}
|
||||||
|
|
||||||
bool Varicode::startsWithCQ(QString text){
|
bool Varicode::startsWithCQ(QString text){
|
||||||
foreach(auto cq, cqs.values()){
|
foreach(auto cq, cqs.values()){
|
||||||
if(text.startsWith(cq)){
|
if(text.startsWith(cq)){
|
||||||
@@ -284,6 +316,15 @@ bool Varicode::startsWithCQ(QString text){
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Varicode::startsWithHB(QString text){
|
||||||
|
foreach(auto cq, hbs.values()){
|
||||||
|
if(text.startsWith(cq)){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QString Varicode::formatSNR(int snr){
|
QString Varicode::formatSNR(int snr){
|
||||||
if(snr < -60 || snr > 60){
|
if(snr < -60 || snr > 60){
|
||||||
return QString();
|
return QString();
|
||||||
@@ -334,6 +375,9 @@ QStringList Varicode::parseCallsigns(QString const &input){
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
QString callsign = match.captured("callsign").trimmed();
|
QString callsign = match.captured("callsign").trimmed();
|
||||||
|
if(!Varicode::isValidCallsign(callsign, nullptr)){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
QRegularExpression m(grid_pattern);
|
QRegularExpression m(grid_pattern);
|
||||||
if(m.match(callsign).hasMatch()){
|
if(m.match(callsign).hasMatch()){
|
||||||
continue;
|
continue;
|
||||||
@@ -621,14 +665,14 @@ QString Varicode::pack72bits(quint64 value, quint8 rem){
|
|||||||
// 21 bits for the data + 1 bit for a flag indicator
|
// 21 bits for the data + 1 bit for a flag indicator
|
||||||
// giving us a total of 5.5 bits per character
|
// giving us a total of 5.5 bits per character
|
||||||
quint32 Varicode::packAlphaNumeric22(QString const& value, bool isFlag){
|
quint32 Varicode::packAlphaNumeric22(QString const& value, bool isFlag){
|
||||||
QString word = QString(value).replace(QRegExp("[^A-Z0-9]"), "");
|
QString word = QString(value).replace(QRegExp("[^A-Z0-9/ ]"), "");
|
||||||
if(word.length() < 4){
|
if(word.length() < 4){
|
||||||
word = word + QString(" ").repeated(4-word.length());
|
word = word + QString(" ").repeated(4-word.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 a = 37 * 37 * 37 * alphanumeric.indexOf(word.at(0));
|
quint32 a = 38 * 38 * 38 * alphanumeric.indexOf(word.at(0));
|
||||||
quint32 b = 37 * 37 * alphanumeric.indexOf(word.at(1));
|
quint32 b = 38 * 38 * alphanumeric.indexOf(word.at(1));
|
||||||
quint32 c = 37 * alphanumeric.indexOf(word.at(2));
|
quint32 c = 38 * alphanumeric.indexOf(word.at(2));
|
||||||
quint32 d = alphanumeric.indexOf(word.at(3));
|
quint32 d = alphanumeric.indexOf(word.at(3));
|
||||||
|
|
||||||
quint32 packed = a + b + c + d;
|
quint32 packed = a + b + c + d;
|
||||||
@@ -643,25 +687,116 @@ QString Varicode::unpackAlphaNumeric22(quint32 packed, bool *isFlag){
|
|||||||
if(isFlag) *isFlag = packed & 1;
|
if(isFlag) *isFlag = packed & 1;
|
||||||
packed = packed >> 1;
|
packed = packed >> 1;
|
||||||
|
|
||||||
quint32 tmp = packed % 37;
|
quint32 tmp = packed % 38;
|
||||||
word[3] = alphanumeric.at(tmp);
|
word[3] = alphanumeric.at(tmp);
|
||||||
packed = packed / 37;
|
packed = packed / 38;
|
||||||
|
|
||||||
tmp = packed % 37;
|
tmp = packed % 38;
|
||||||
word[2] = alphanumeric.at(tmp);
|
word[2] = alphanumeric.at(tmp);
|
||||||
packed = packed / 37;
|
packed = packed / 38;
|
||||||
|
|
||||||
tmp = packed % 37;
|
tmp = packed % 38;
|
||||||
word[1] = alphanumeric.at(tmp);
|
word[1] = alphanumeric.at(tmp);
|
||||||
packed = packed / 37;
|
packed = packed / 38;
|
||||||
|
|
||||||
tmp = packed % 37;
|
tmp = packed % 38;
|
||||||
word[0] = alphanumeric.at(tmp);
|
word[0] = alphanumeric.at(tmp);
|
||||||
packed = packed / 37;
|
packed = packed / 38;
|
||||||
|
|
||||||
return QString(word, 4);
|
return QString(word, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pack a 10-digit alpha-numeric + space + forward-slash into a 50 bit value
|
||||||
|
// optionally start with an @
|
||||||
|
//
|
||||||
|
// [39][38][38][02][38][38][38][02][38][38][38]
|
||||||
|
// [K] [N] [4] [ ] [C] [R] [D] [/] [Q] [R] [P]
|
||||||
|
// [V] [E] [3] [/] [L] [B] [9] [ ] [Y] [H] [X]
|
||||||
|
// [@] [R] [A] [ ] [C] [E] [S] [ ] [ ] [ ] [ ]
|
||||||
|
//
|
||||||
|
// giving us a total of 4.5-5.55 bits per character
|
||||||
|
quint64 Varicode::packAlphaNumeric50(QString const& value){
|
||||||
|
QString word = QString(value).replace(QRegExp("[^A-Z0-9 /@]"), "");
|
||||||
|
if(word.length() > 3 && word.at(3) != '/'){
|
||||||
|
word.insert(3, ' ');
|
||||||
|
}
|
||||||
|
if(word.length() > 7 && word.at(7) != '/'){
|
||||||
|
word.insert(7, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(word.length() < 11){
|
||||||
|
word = word + QString(" ").repeated(11-word.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
quint64 a = (quint64)38 * 38 * 38 * 2 * 38 * 38 * 38 * 2 * 38 * 38 * alphanumeric.indexOf(word.at(0));
|
||||||
|
quint64 b = (quint64)38 * 38 * 38 * 2 * 38 * 38 * 38 * 2 * 38 * alphanumeric.indexOf(word.at(1));
|
||||||
|
quint64 c = (quint64)38 * 38 * 38 * 2 * 38 * 38 * 38 * 2 * alphanumeric.indexOf(word.at(2));
|
||||||
|
quint64 d = (quint64)38 * 38 * 38 * 2 * 38 * 38 * 38 * (int)(word.at(3) == '/');
|
||||||
|
quint64 e = (quint64)38 * 38 * 38 * 2 * 38 * 38 * alphanumeric.indexOf(word.at(4));
|
||||||
|
quint64 f = (quint64)38 * 38 * 38 * 2 * 38 * alphanumeric.indexOf(word.at(5));
|
||||||
|
quint64 g = (quint64)38 * 38 * 38 * 2 * alphanumeric.indexOf(word.at(6));
|
||||||
|
quint64 h = (quint64)38 * 38 * 38 * (int)(word.at(7) == '/');
|
||||||
|
quint64 i = (quint64)38 * 38 * alphanumeric.indexOf(word.at(8));
|
||||||
|
quint64 j = (quint64)38 * alphanumeric.indexOf(word.at(9));
|
||||||
|
quint64 k = (quint64)alphanumeric.indexOf(word.at(10));
|
||||||
|
|
||||||
|
quint64 packed = a + b + c + d + e + f + g + h + i + j + k;
|
||||||
|
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Varicode::unpackAlphaNumeric50(quint64 packed){
|
||||||
|
QChar word[11];
|
||||||
|
|
||||||
|
quint64 tmp = packed % 38;
|
||||||
|
word[10] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 38;
|
||||||
|
|
||||||
|
tmp = packed % 38;
|
||||||
|
word[9] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 38;
|
||||||
|
|
||||||
|
tmp = packed % 38;
|
||||||
|
word[8] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 38;
|
||||||
|
|
||||||
|
tmp = packed % 2;
|
||||||
|
word[7] = tmp ? '/' : ' ';
|
||||||
|
packed = packed / 2;
|
||||||
|
|
||||||
|
tmp = packed % 38;
|
||||||
|
word[6] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 38;
|
||||||
|
|
||||||
|
tmp = packed % 38;
|
||||||
|
word[5] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 38;
|
||||||
|
|
||||||
|
tmp = packed % 38;
|
||||||
|
word[4] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 38;
|
||||||
|
|
||||||
|
tmp = packed % 2;
|
||||||
|
word[3] = tmp ? '/' : ' ';
|
||||||
|
packed = packed / 2;
|
||||||
|
|
||||||
|
tmp = packed % 38;
|
||||||
|
word[2] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 38;
|
||||||
|
|
||||||
|
tmp = packed % 38;
|
||||||
|
word[1] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 38;
|
||||||
|
|
||||||
|
tmp = packed % 39;
|
||||||
|
word[0] = alphanumeric.at(tmp);
|
||||||
|
packed = packed / 39;
|
||||||
|
|
||||||
|
auto value = QString(word, 11);
|
||||||
|
|
||||||
|
return value.replace(" ", "");
|
||||||
|
}
|
||||||
|
|
||||||
// pack a callsign into a 28-bit value
|
// pack a callsign into a 28-bit value
|
||||||
quint32 Varicode::packCallsign(QString const& value){
|
quint32 Varicode::packCallsign(QString const& value){
|
||||||
quint32 packed = 0;
|
quint32 packed = 0;
|
||||||
@@ -882,8 +1017,8 @@ quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
|
|||||||
// 8 bits - 1 bit flag + 1 bit type + 6 bit number
|
// 8 bits - 1 bit flag + 1 bit type + 6 bit number
|
||||||
// [1][X][6]
|
// [1][X][6]
|
||||||
// X = 0 == SNR
|
// X = 0 == SNR
|
||||||
// X = 1 == BEACON ACK
|
// X = 1 == ACK
|
||||||
value = ((1 << 1) | (int)(cmdStr == " BEACON ACK")) << 6;
|
value = ((1 << 1) | (int)(cmdStr == " ACK")) << 6;
|
||||||
value = value + (num & ((1<<6)-1));
|
value = value + (num & ((1<<6)-1));
|
||||||
if(pPackedNum) *pPackedNum = true;
|
if(pPackedNum) *pPackedNum = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -901,7 +1036,7 @@ quint8 Varicode::unpackCmd(quint8 value, quint8 *pNum){
|
|||||||
|
|
||||||
auto cmd = directed_cmds[" SNR"];
|
auto cmd = directed_cmds[" SNR"];
|
||||||
if(value & (1<<6)){
|
if(value & (1<<6)){
|
||||||
cmd = directed_cmds[" BEACON ACK"];
|
cmd = directed_cmds[" ACK"];
|
||||||
}
|
}
|
||||||
return cmd;
|
return cmd;
|
||||||
} else {
|
} else {
|
||||||
@@ -930,14 +1065,92 @@ int Varicode::isCommandChecksumed(const QString &cmd){
|
|||||||
return checksum_cmds[directed_cmds[cmd]];
|
return checksum_cmds[directed_cmds[cmd]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isValidCompoundCallsign(QStringRef callsign){
|
||||||
|
// compound calls cannot be > 9 characters after removing the /
|
||||||
|
if(callsign.toString().replace("/", "").length() > 9){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compound is valid when it is:
|
||||||
|
// 1) a group call (starting with @)
|
||||||
|
// 2) an actual compound call (containing /) that is not a base call
|
||||||
|
// 3) is greater than two characters and has an alphanumeric character sequence
|
||||||
|
//
|
||||||
|
// this is so arbitrary words < 10 characters in length don't end up coded as callsigns
|
||||||
|
if(callsign.contains("/")){
|
||||||
|
auto base = callsign.toString().left(callsign.indexOf("/"));
|
||||||
|
return !basecalls.contains(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(callsign.startsWith("@")){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(callsign.length() > 2 && QRegularExpression("[0-9][A-Z]|[A-Z][0-9]").match(callsign).hasMatch()){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Varicode::isValidCallsign(const QString &callsign, bool *pIsCompound){
|
||||||
|
if(basecalls.contains(callsign)){
|
||||||
|
if(pIsCompound) *pIsCompound = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto match = QRegularExpression(base_callsign_pattern).match(callsign);
|
||||||
|
if(match.hasMatch() && (match.capturedLength() == callsign.length())){
|
||||||
|
if(pIsCompound) *pIsCompound = false;
|
||||||
|
return callsign.length() > 2 && QRegularExpression("[0-9][A-Z]|[A-Z][0-9]").match(callsign).hasMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
match = QRegularExpression("^" + compound_callsign_pattern).match(callsign);
|
||||||
|
|
||||||
|
if(match.hasMatch() && (match.capturedLength() == callsign.length())){
|
||||||
|
bool isValid = isValidCompoundCallsign(match.capturedRef(0));
|
||||||
|
|
||||||
|
qDebug() << "is valid compound??" << match.capturedRef(0) << isValid;
|
||||||
|
|
||||||
|
if(pIsCompound) *pIsCompound = isValid;
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pIsCompound) *pIsCompound = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Varicode::isCompoundCallsign(const QString &callsign){
|
||||||
|
if(basecalls.contains(callsign)){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto match = QRegularExpression(base_callsign_pattern).match(callsign);
|
||||||
|
if(match.hasMatch() && (match.capturedLength() == callsign.length())){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
match = QRegularExpression("^" + compound_callsign_pattern).match(callsign);
|
||||||
|
if(!match.hasMatch() || (match.capturedLength() != callsign.length())){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid = isValidCompoundCallsign(match.capturedRef(0));
|
||||||
|
|
||||||
|
qDebug() << "is valid compound?" << match.capturedRef(0) << isValid;
|
||||||
|
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
// CQCQCQ EM73
|
// CQCQCQ EM73
|
||||||
// CQ DX EM73
|
// CQ DX EM73
|
||||||
// CQ QRP EM73
|
// CQ QRP EM73
|
||||||
// BEACON EM73
|
// HB ACTIVE EM73
|
||||||
QString Varicode::packBeaconMessage(QString const &text, const QString &callsign, int *n){
|
// HB IDLE EM73
|
||||||
|
QString Varicode::packHeartbeatMessage(QString const &text, const QString &callsign, int *n){
|
||||||
QString frame;
|
QString frame;
|
||||||
|
|
||||||
auto parsedText = beacon_re.match(text);
|
auto parsedText = heartbeat_re.match(text);
|
||||||
if(!parsedText.hasMatch()){
|
if(!parsedText.hasMatch()){
|
||||||
if(n) *n = 0;
|
if(n) *n = 0;
|
||||||
return frame;
|
return frame;
|
||||||
@@ -945,44 +1158,32 @@ QString Varicode::packBeaconMessage(QString const &text, const QString &callsign
|
|||||||
|
|
||||||
auto extra = parsedText.captured("grid");
|
auto extra = parsedText.captured("grid");
|
||||||
|
|
||||||
// Beacon Alt Type
|
// Heartbeat Alt Type
|
||||||
// ---------------
|
// ---------------
|
||||||
// 1 0 BEACON
|
// 1 0 HB
|
||||||
// 1 1 CQCQCQ
|
// 1 1 CQ
|
||||||
|
|
||||||
auto type = parsedText.captured("type");
|
auto type = parsedText.captured("type");
|
||||||
auto isAlt = type.startsWith("CQ");
|
auto isAlt = type.startsWith("CQ");
|
||||||
|
|
||||||
auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign);
|
if(callsign.isEmpty()){
|
||||||
if(!parsedCall.hasMatch()){
|
|
||||||
if(n) *n = 0;
|
if(n) *n = 0;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString base = parsedCall.captured("base");
|
|
||||||
|
|
||||||
bool isPrefix = false;
|
|
||||||
QString fix = parsedCall.captured("prefix");
|
|
||||||
if(!fix.isEmpty()){
|
|
||||||
isPrefix = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!isPrefix){
|
|
||||||
fix = parsedCall.captured("suffix");
|
|
||||||
}
|
|
||||||
|
|
||||||
quint16 packed_extra = nmaxgrid; // which will display an empty string
|
quint16 packed_extra = nmaxgrid; // which will display an empty string
|
||||||
if(extra.length() == 4 && QRegularExpression(grid_pattern).match(extra).hasMatch()){
|
if(extra.length() == 4 && QRegularExpression(grid_pattern).match(extra).hasMatch()){
|
||||||
packed_extra = Varicode::packGrid(extra);
|
packed_extra = Varicode::packGrid(extra);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quint8 cqNumber = hbs.key(type, 0);
|
||||||
|
|
||||||
if(isAlt){
|
if(isAlt){
|
||||||
packed_extra |= (1<<15);
|
packed_extra |= (1<<15);
|
||||||
|
cqNumber = cqs.key(type, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
quint8 cqNumber = cqs.key(type, 0);
|
frame = packCompoundFrame(callsign, FrameHeartbeat, packed_extra, cqNumber);
|
||||||
|
|
||||||
frame = packCompoundFrame(base, fix, isPrefix, FrameBeacon, packed_extra, cqNumber);
|
|
||||||
if(frame.isEmpty()){
|
if(frame.isEmpty()){
|
||||||
if(n) *n = 0;
|
if(n) *n = 0;
|
||||||
return frame;
|
return frame;
|
||||||
@@ -992,13 +1193,13 @@ QString Varicode::packBeaconMessage(QString const &text, const QString &callsign
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList Varicode::unpackBeaconMessage(const QString &text, quint8 *pType, bool * isAlt, quint8 * pBits3){
|
QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType, bool * isAlt, quint8 * pBits3){
|
||||||
quint8 type = FrameBeacon;
|
quint8 type = FrameHeartbeat;
|
||||||
quint16 num = nmaxgrid;
|
quint16 num = nmaxgrid;
|
||||||
quint8 bits3 = 0;
|
quint8 bits3 = 0;
|
||||||
|
|
||||||
QStringList unpacked = unpackCompoundFrame(text, &type, &num, &bits3);
|
QStringList unpacked = unpackCompoundFrame(text, &type, &num, &bits3);
|
||||||
if(unpacked.isEmpty() || type != FrameBeacon){
|
if(unpacked.isEmpty() || type != FrameHeartbeat){
|
||||||
return QStringList{};
|
return QStringList{};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1021,7 +1222,7 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
|
|||||||
qDebug() << "trying to pack compound message" << text;
|
qDebug() << "trying to pack compound message" << text;
|
||||||
auto parsedText = compound_re.match(text);
|
auto parsedText = compound_re.match(text);
|
||||||
if(!parsedText.hasMatch()){
|
if(!parsedText.hasMatch()){
|
||||||
qDebug() << "no match for compound message";
|
qDebug() << "no match for compound message" << text;
|
||||||
if(n) *n = 0;
|
if(n) *n = 0;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
@@ -1033,30 +1234,9 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
|
|||||||
QString cmd = parsedText.captured("cmd");
|
QString cmd = parsedText.captured("cmd");
|
||||||
QString num = parsedText.captured("num").trimmed();
|
QString num = parsedText.captured("num").trimmed();
|
||||||
|
|
||||||
QString base;
|
if(callsign.isEmpty()){
|
||||||
QString fix;
|
if(n) *n = 0;
|
||||||
bool isPrefix = false;
|
return frame;
|
||||||
|
|
||||||
if(basecalls.contains(callsign)){
|
|
||||||
// if it's a basecall, use it verbatim with no prefix/suffix
|
|
||||||
base = callsign;
|
|
||||||
fix = "";
|
|
||||||
} else {
|
|
||||||
// otherwise, parse the callsign for prefix/suffix
|
|
||||||
auto parsedCall = QRegularExpression(compound_callsign_pattern).match(callsign);
|
|
||||||
if(!parsedCall.hasMatch()){
|
|
||||||
if(n) *n = 0;
|
|
||||||
return frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
base = parsedCall.captured("base");
|
|
||||||
fix = parsedCall.captured("prefix");
|
|
||||||
if(!fix.isEmpty()){
|
|
||||||
isPrefix = true;
|
|
||||||
}
|
|
||||||
if(!isPrefix){
|
|
||||||
fix = parsedCall.captured("suffix");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint8 type = FrameCompound;
|
quint8 type = FrameCompound;
|
||||||
@@ -1074,7 +1254,7 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
|
|||||||
extra = Varicode::packGrid(grid);
|
extra = Varicode::packGrid(grid);
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = Varicode::packCompoundFrame(base, fix, isPrefix, type, extra, 0);
|
frame = Varicode::packCompoundFrame(callsign, type, extra, 0);
|
||||||
|
|
||||||
if(n) *n = parsedText.captured(0).length();
|
if(n) *n = parsedText.captured(0).length();
|
||||||
return frame;
|
return frame;
|
||||||
@@ -1110,7 +1290,7 @@ QStringList Varicode::unpackCompoundMessage(const QString &text, quint8 *pType,
|
|||||||
return unpacked;
|
return unpacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Varicode::packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, quint8 type, quint16 num, quint8 bits3){
|
QString Varicode::packCompoundFrame(const QString &callsign, quint8 type, quint16 num, quint8 bits3){
|
||||||
QString frame;
|
QString frame;
|
||||||
|
|
||||||
// needs to be a compound type...
|
// needs to be a compound type...
|
||||||
@@ -1119,10 +1299,8 @@ QString Varicode::packCompoundFrame(const QString &baseCallsign, const QString &
|
|||||||
}
|
}
|
||||||
|
|
||||||
quint8 packed_flag = type;
|
quint8 packed_flag = type;
|
||||||
quint32 packed_base = Varicode::packCallsign(baseCallsign);
|
quint64 packed_callsign = Varicode::packAlphaNumeric50(callsign);
|
||||||
quint32 packed_fix = Varicode::packAlphaNumeric22(fix, isPrefix);
|
if(packed_callsign == 0){
|
||||||
|
|
||||||
if(packed_base == 0 || packed_fix == 0){
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1133,11 +1311,10 @@ QString Varicode::packCompoundFrame(const QString &baseCallsign, const QString &
|
|||||||
quint8 packed_5 = num & mask5;
|
quint8 packed_5 = num & mask5;
|
||||||
quint8 packed_8 = (packed_5 << 3) | bits3;
|
quint8 packed_8 = (packed_5 << 3) | bits3;
|
||||||
|
|
||||||
// [3][28][22][11],[5][3] = 72
|
// [3][50][11],[5][3] = 72
|
||||||
auto bits = (
|
auto bits = (
|
||||||
Varicode::intToBits(packed_flag, 3) +
|
Varicode::intToBits(packed_flag, 3) +
|
||||||
Varicode::intToBits(packed_base, 28) +
|
Varicode::intToBits(packed_callsign, 50) +
|
||||||
Varicode::intToBits(packed_fix, 22) +
|
|
||||||
Varicode::intToBits(packed_11, 11)
|
Varicode::intToBits(packed_11, 11)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1151,7 +1328,7 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, quint8 *pType, qu
|
|||||||
return unpacked;
|
return unpacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
// [3][28][22][11],[5][3] = 72
|
// [3][50][11],[5][3] = 72
|
||||||
quint8 packed_8 = 0;
|
quint8 packed_8 = 0;
|
||||||
auto bits = Varicode::intToBits(Varicode::unpack72bits(text, &packed_8), 64);
|
auto bits = Varicode::intToBits(Varicode::unpack72bits(text, &packed_8), 64);
|
||||||
|
|
||||||
@@ -1160,19 +1337,15 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, quint8 *pType, qu
|
|||||||
|
|
||||||
quint8 packed_flag = Varicode::bitsToInt(bits.mid(0, 3));
|
quint8 packed_flag = Varicode::bitsToInt(bits.mid(0, 3));
|
||||||
|
|
||||||
// needs to be a beacon type...
|
// needs to be a ping type...
|
||||||
if(packed_flag == FrameDataCompressed || packed_flag == FrameDataUncompressed || packed_flag == FrameDirected){
|
if(packed_flag == FrameDataCompressed || packed_flag == FrameDataUncompressed || packed_flag == FrameDirected){
|
||||||
return unpacked;
|
return unpacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
quint32 packed_base = Varicode::bitsToInt(bits.mid(3, 28));
|
quint64 packed_callsign = Varicode::bitsToInt(bits.mid(3, 50));
|
||||||
quint32 packed_fix = Varicode::bitsToInt(bits.mid(31, 22));
|
|
||||||
quint16 packed_11 = Varicode::bitsToInt(bits.mid(53, 11));
|
quint16 packed_11 = Varicode::bitsToInt(bits.mid(53, 11));
|
||||||
|
|
||||||
QString base = Varicode::unpackCallsign(packed_base).trimmed();
|
QString callsign = Varicode::unpackAlphaNumeric50(packed_callsign);
|
||||||
|
|
||||||
bool isPrefix = false;
|
|
||||||
QString fix = Varicode::unpackAlphaNumeric22(packed_fix, &isPrefix).trimmed();
|
|
||||||
|
|
||||||
quint16 num = (packed_11 << 5) | packed_5;
|
quint16 num = (packed_11 << 5) | packed_5;
|
||||||
|
|
||||||
@@ -1180,15 +1353,8 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, quint8 *pType, qu
|
|||||||
if(pNum) *pNum = num;
|
if(pNum) *pNum = num;
|
||||||
if(pBits3) *pBits3 = packed_3;
|
if(pBits3) *pBits3 = packed_3;
|
||||||
|
|
||||||
if(isPrefix){
|
unpacked.append(callsign);
|
||||||
unpacked.append(fix);
|
unpacked.append("");
|
||||||
}
|
|
||||||
|
|
||||||
unpacked.append(base);
|
|
||||||
|
|
||||||
if(!isPrefix){
|
|
||||||
unpacked.append(fix);
|
|
||||||
}
|
|
||||||
|
|
||||||
return unpacked;
|
return unpacked;
|
||||||
}
|
}
|
||||||
@@ -1197,7 +1363,7 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, quint8 *pType, qu
|
|||||||
// J1Y?
|
// J1Y?
|
||||||
// KN4CRD: J1Y$
|
// KN4CRD: J1Y$
|
||||||
// KN4CRD: J1Y! HELLO WORLD
|
// KN4CRD: J1Y! HELLO WORLD
|
||||||
QString Varicode::packDirectedMessage(const QString &text, const QString &callsign, QString *pTo, QString * pCmd, QString *pNum, int *n){
|
QString Varicode::packDirectedMessage(const QString &text, const QString &mycall, QString *pTo, bool *pToCompound, QString * pCmd, QString *pNum, int *n){
|
||||||
QString frame;
|
QString frame;
|
||||||
|
|
||||||
auto match = directed_re.match(text);
|
auto match = directed_re.match(text);
|
||||||
@@ -1206,7 +1372,11 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString from = callsign;
|
QString from = mycall;
|
||||||
|
bool isFromCompound = Varicode::isCompoundCallsign(from);
|
||||||
|
if(isFromCompound){
|
||||||
|
from = "<....>";
|
||||||
|
}
|
||||||
QString to = match.captured("callsign");
|
QString to = match.captured("callsign");
|
||||||
QString cmd = match.captured("cmd");
|
QString cmd = match.captured("cmd");
|
||||||
QString num = match.captured("num");
|
QString num = match.captured("num");
|
||||||
@@ -1217,25 +1387,27 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
|
|||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate "to" callsign
|
// ensure we have a valid callsign
|
||||||
auto parsedTo = QRegularExpression(compound_callsign_pattern).match(to);
|
bool isToCompound = false;
|
||||||
bool validToCallsign = (to != callsign) && (basecalls.contains(to) || parsedTo.hasMatch());
|
bool validToCallsign = (to != mycall) && Varicode::isValidCallsign(to, &isToCompound);
|
||||||
if(!validToCallsign){
|
if(!validToCallsign){
|
||||||
|
qDebug() << "to" << to << "is not a valid callsign";
|
||||||
if(n) *n = 0;
|
if(n) *n = 0;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(basecalls.contains(to)){
|
// return back the parsed "to" field
|
||||||
if(pTo) *pTo = to;
|
if(pTo) *pTo = to;
|
||||||
} else if(parsedTo.hasMatch()){
|
if(pToCompound) *pToCompound = isToCompound;
|
||||||
if(pTo) *pTo = parsedTo.captured(0);
|
|
||||||
|
|
||||||
auto parsedBase = parsedTo.captured("base");
|
// then replace the current processing with a placeholder that we _can_ pack into a directed command,
|
||||||
if(parsedBase.length() != to.length()){
|
// because later we'll send the "to" field in a compound frame using the results of this directed pack
|
||||||
to = "<....>"; // parsedBase;
|
if(isToCompound){
|
||||||
}
|
to = "<....>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDebug() << "directed" << validToCallsign << isToCompound << to;
|
||||||
|
|
||||||
// validate command
|
// validate command
|
||||||
if(!Varicode::isCommandAllowed(cmd) && !Varicode::isCommandAllowed(cmd.trimmed())){
|
if(!Varicode::isCommandAllowed(cmd) && !Varicode::isCommandAllowed(cmd.trimmed())){
|
||||||
if(n) *n = 0;
|
if(n) *n = 0;
|
||||||
@@ -1328,10 +1500,8 @@ QString packHuffMessage(const QString &input, int *n){
|
|||||||
|
|
||||||
QString frame;
|
QString frame;
|
||||||
|
|
||||||
// [3][69] = 72
|
// [1][71] = 72
|
||||||
QVector<bool> frameDataBits;
|
QVector<bool> frameBits = {false};
|
||||||
|
|
||||||
QVector<bool> frameHeaderBits = Varicode::intToBits(Varicode::FrameDataUncompressed, 3);
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
@@ -1341,6 +1511,7 @@ QString packHuffMessage(const QString &input, int *n){
|
|||||||
for(it = input.constBegin(); it != input.constEnd(); it++){
|
for(it = input.constBegin(); it != input.constEnd(); it++){
|
||||||
auto ch = (*it).toUpper();
|
auto ch = (*it).toUpper();
|
||||||
if(!validChars.contains(ch)){
|
if(!validChars.contains(ch)){
|
||||||
|
if(n) *n = 0;
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1349,32 +1520,28 @@ QString packHuffMessage(const QString &input, int *n){
|
|||||||
foreach(auto pair, Varicode::huffEncode(Varicode::defaultHuffTable(), input)){
|
foreach(auto pair, Varicode::huffEncode(Varicode::defaultHuffTable(), input)){
|
||||||
auto charN = pair.first;
|
auto charN = pair.first;
|
||||||
auto charBits = pair.second;
|
auto charBits = pair.second;
|
||||||
if(frameHeaderBits.length() + frameDataBits.length() + charBits.length() < frameSize){
|
if(frameBits.length() + charBits.length() < frameSize){
|
||||||
frameDataBits += charBits;
|
frameBits += charBits;
|
||||||
i += charN;
|
i += charN;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
QVector<bool> framePadBits;
|
qDebug() << "Huff bits" << frameBits.length() << "chars" << i;
|
||||||
|
|
||||||
int pad = frameSize - frameHeaderBits.length() - frameDataBits.length();
|
int pad = frameSize - frameBits.length();
|
||||||
if(pad){
|
if(pad){
|
||||||
// the way we will pad is this...
|
// the way we will pad is this...
|
||||||
// set the bit after the frame to 0 and every bit after that a 1
|
// set the bit after the frame to 0 and every bit after that a 1
|
||||||
// to unpad, seek from the end of the bits until you hit a zero... the rest is the actual frame.
|
// to unpad, seek from the end of the bits until you hit a zero... the rest is the actual frame.
|
||||||
for(int i = 0; i < pad; i++){
|
for(int i = 0; i < pad; i++){
|
||||||
framePadBits.append(i == 0 ? (bool)0 : (bool)1);
|
frameBits.append(i == 0 ? (bool)0 : (bool)1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Huff bits" << frameDataBits.length() << "chars" << i;
|
quint64 value = Varicode::bitsToInt(frameBits.constBegin(), 64);
|
||||||
|
quint8 rem = (quint8)Varicode::bitsToInt(frameBits.constBegin() + 64, 8);
|
||||||
QVector<bool> allBits = frameHeaderBits + frameDataBits + framePadBits;
|
|
||||||
|
|
||||||
quint64 value = Varicode::bitsToInt(allBits.constBegin(), 64);
|
|
||||||
quint8 rem = (quint8)Varicode::bitsToInt(allBits.constBegin() + 64, 8);
|
|
||||||
frame = Varicode::pack72bits(value, rem);
|
frame = Varicode::pack72bits(value, rem);
|
||||||
|
|
||||||
if(n) *n = i;
|
if(n) *n = i;
|
||||||
@@ -1387,9 +1554,8 @@ QString packCompressedMessage(const QString &input, int *n){
|
|||||||
|
|
||||||
QString frame;
|
QString frame;
|
||||||
|
|
||||||
QVector<bool> frameBits;
|
// [1][71] = 72
|
||||||
|
QVector<bool> frameBits = {true};
|
||||||
frameBits.append(Varicode::intToBits(Varicode::FrameDataCompressed, 3));
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach(auto pair, JSC::compress(input)){
|
foreach(auto pair, JSC::compress(input)){
|
||||||
@@ -1405,7 +1571,7 @@ QString packCompressedMessage(const QString &input, int *n){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
qDebug() << "Compressed bits" << frameBits.length() - 3 << "chars" << i;
|
qDebug() << "Compressed bits" << frameBits.length() << "chars" << i;
|
||||||
|
|
||||||
int pad = frameSize - frameBits.length();
|
int pad = frameSize - frameBits.length();
|
||||||
if(pad){
|
if(pad){
|
||||||
@@ -1455,36 +1621,41 @@ QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
|
|||||||
quint64 value = Varicode::unpack72bits(text, &rem);
|
quint64 value = Varicode::unpack72bits(text, &rem);
|
||||||
auto bits = Varicode::intToBits(value, 64) + Varicode::intToBits(rem, 8);
|
auto bits = Varicode::intToBits(value, 64) + Varicode::intToBits(rem, 8);
|
||||||
|
|
||||||
quint8 type = Varicode::bitsToInt(bits.mid(0, 3));
|
bool compressed = bits.at(0);
|
||||||
|
|
||||||
int n = bits.lastIndexOf(0);
|
int n = bits.lastIndexOf(0);
|
||||||
bits = bits.mid(3, n-3);
|
bits = bits.mid(1, n-1);
|
||||||
|
|
||||||
if(type == FrameDataUncompressed){
|
if(compressed){
|
||||||
|
unpacked = JSC::decompress(bits);
|
||||||
|
if(pType) *pType = Varicode::FrameDataCompressed;
|
||||||
|
} else {
|
||||||
// huff decode the bits (without escapes)
|
// huff decode the bits (without escapes)
|
||||||
unpacked = Varicode::huffDecode(Varicode::defaultHuffTable(), bits);
|
unpacked = Varicode::huffDecode(Varicode::defaultHuffTable(), bits);
|
||||||
if(pType) *pType = type;
|
if(pType) *pType = Varicode::FrameDataUncompressed;
|
||||||
} else if(type == FrameDataCompressed) {
|
|
||||||
unpacked = JSC::decompress(bits);
|
|
||||||
if(pType) *pType = type;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return unpacked;
|
return unpacked;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove the dependence on providing all this data?
|
// TODO: remove the dependence on providing all this data?
|
||||||
QStringList Varicode::buildMessageFrames(
|
QList<QPair<QString, int>> Varicode::buildMessageFrames(
|
||||||
QString const& mycall,
|
QString const& mycall,
|
||||||
QString const& basecall,
|
//QString const& basecall,
|
||||||
QString const& mygrid,
|
QString const& mygrid,
|
||||||
bool compound,
|
//bool compound,
|
||||||
QString const& selectedCall,
|
QString const& selectedCall,
|
||||||
QString const& text
|
QString const& text
|
||||||
){
|
){
|
||||||
#define ALLOW_SEND_COMPOUND 1
|
#define ALLOW_SEND_COMPOUND 1
|
||||||
|
#define ALLOW_SEND_COMPOUND_DIRECTED 1
|
||||||
#define AUTO_PREPEND_DIRECTED 1
|
#define AUTO_PREPEND_DIRECTED 1
|
||||||
|
#define AUTO_REMOVE_MYCALL 1
|
||||||
|
#define AUTO_PREPEND_DIRECTED_ALLOW_TEXT_CALLSIGNS 1
|
||||||
|
|
||||||
QStringList frames;
|
bool mycallCompound = Varicode::isCompoundCallsign(mycall);
|
||||||
|
|
||||||
|
QList<QPair<QString, int>> frames;
|
||||||
|
|
||||||
foreach(QString line, text.split(QRegExp("[\\r\\n]"), QString::SkipEmptyParts)){
|
foreach(QString line, text.split(QRegExp("[\\r\\n]"), QString::SkipEmptyParts)){
|
||||||
// once we find a directed call, data encode the rest of the line.
|
// once we find a directed call, data encode the rest of the line.
|
||||||
@@ -1493,35 +1664,36 @@ QStringList Varicode::buildMessageFrames(
|
|||||||
// do the same for when we have sent data...
|
// do the same for when we have sent data...
|
||||||
bool hasData = false;
|
bool hasData = false;
|
||||||
|
|
||||||
|
#if AUTO_REMOVE_MYCALL
|
||||||
// remove our callsign from the start of the line...
|
// remove our callsign from the start of the line...
|
||||||
if(line.startsWith(mycall + ":") || line.startsWith(mycall + " ")){
|
if(line.startsWith(mycall + ":") || line.startsWith(mycall + " ")){
|
||||||
line = lstrip(line.mid(mycall.length() + 1));
|
line = lstrip(line.mid(mycall.length() + 1));
|
||||||
}
|
}
|
||||||
if(line.startsWith(basecall + ":") || line.startsWith(basecall + " ")){
|
|
||||||
line = lstrip(line.mid(basecall.length() + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove trailing whitespace as long as there are characters left afterwards
|
// remove trailing whitespace as long as there are characters left afterwards
|
||||||
auto rline = rstrip(line);
|
auto rline = rstrip(line);
|
||||||
if(!rline.isEmpty()){
|
if(!rline.isEmpty()){
|
||||||
line = rline;
|
line = rline;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if AUTO_PREPEND_DIRECTED
|
#if AUTO_PREPEND_DIRECTED
|
||||||
// see if we need to prepend the directed call to the line...
|
// see if we need to prepend the directed call to the line...
|
||||||
// if we have a selected call and the text doesn't start with that call...
|
// if we have a selected call and the text doesn't start with that call...
|
||||||
// and if this isn't a raw message (starting with "`")... then...
|
// and if this isn't a raw message (starting with "`")... then...
|
||||||
if(!selectedCall.isEmpty() && !line.startsWith(selectedCall) && !line.startsWith("`")){
|
if(!selectedCall.isEmpty() && !line.startsWith(selectedCall) && !line.startsWith("`")){
|
||||||
auto calls = Varicode::parseCallsigns(line);
|
|
||||||
|
|
||||||
bool lineStartsWithBaseCall = (
|
bool lineStartsWithBaseCall = (
|
||||||
line.startsWith("ALLCALL") ||
|
line.startsWith("@ALLCALL") ||
|
||||||
line.startsWith("GROUPCALL") ||
|
Varicode::startsWithCQ(line) ||
|
||||||
line.startsWith("BEACON") ||
|
Varicode::startsWithHB(line)
|
||||||
Varicode::startsWithCQ(line)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#if AUTO_PREPEND_DIRECTED_ALLOW_TEXT_CALLSIGNS
|
||||||
|
auto calls = Varicode::parseCallsigns(line);
|
||||||
bool lineStartsWithStandardCall = !calls.isEmpty() && line.startsWith(calls.first()) && calls.first().length() > 2;
|
bool lineStartsWithStandardCall = !calls.isEmpty() && line.startsWith(calls.first()) && calls.first().length() > 2;
|
||||||
|
#else
|
||||||
|
bool lineStartsWithStandardCall = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
if(lineStartsWithBaseCall || lineStartsWithStandardCall){
|
if(lineStartsWithBaseCall || lineStartsWithStandardCall){
|
||||||
// pass
|
// pass
|
||||||
@@ -1547,7 +1719,7 @@ QStringList Varicode::buildMessageFrames(
|
|||||||
bool useDat = false;
|
bool useDat = false;
|
||||||
|
|
||||||
int l = 0;
|
int l = 0;
|
||||||
QString bcnFrame = Varicode::packBeaconMessage(line, mycall, &l);
|
QString bcnFrame = Varicode::packHeartbeatMessage(line, mycall, &l);
|
||||||
|
|
||||||
#if ALLOW_SEND_COMPOUND
|
#if ALLOW_SEND_COMPOUND
|
||||||
int o = 0;
|
int o = 0;
|
||||||
@@ -1558,8 +1730,8 @@ QStringList Varicode::buildMessageFrames(
|
|||||||
QString dirCmd;
|
QString dirCmd;
|
||||||
QString dirTo;
|
QString dirTo;
|
||||||
QString dirNum;
|
QString dirNum;
|
||||||
QString dirFrame = Varicode::packDirectedMessage(line, basecall, &dirTo, &dirCmd, &dirNum, &n);
|
bool dirToCompound = false;
|
||||||
bool dirToCompound = dirTo.contains("/");
|
QString dirFrame = Varicode::packDirectedMessage(line, mycall, &dirTo, &dirToCompound, &dirCmd, &dirNum, &n);
|
||||||
if(dirToCompound){
|
if(dirToCompound){
|
||||||
qDebug() << "directed message to field is compound" << dirTo;
|
qDebug() << "directed message to field is compound" << dirTo;
|
||||||
}
|
}
|
||||||
@@ -1597,18 +1769,21 @@ QStringList Varicode::buildMessageFrames(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(useBcn){
|
if(useBcn){
|
||||||
frames.append(frame);
|
frames.append({ frame, Varicode::JS8Call });
|
||||||
line = line.mid(l);
|
line = line.mid(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ALLOW_SEND_COMPOUND
|
#if ALLOW_SEND_COMPOUND
|
||||||
if(useCmp){
|
if(useCmp){
|
||||||
frames.append(frame);
|
frames.append({ frame, Varicode::JS8Call });
|
||||||
line = line.mid(o);
|
line = line.mid(o);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(useDir){
|
if(useDir){
|
||||||
|
bool shouldUseStandardFrame = true;
|
||||||
|
|
||||||
|
#if ALLOW_SEND_COMPOUND_DIRECTED
|
||||||
/**
|
/**
|
||||||
* We have a few special cases when we are sending to a compound call, or our call is a compound call, or both.
|
* We have a few special cases when we are sending to a compound call, or our call is a compound call, or both.
|
||||||
* CASE 0: Non-compound: KN4CRD: J1Y ACK
|
* CASE 0: Non-compound: KN4CRD: J1Y ACK
|
||||||
@@ -1628,27 +1803,28 @@ QStringList Varicode::buildMessageFrames(
|
|||||||
* -> One standard compound frame, followed by a compound directed frame
|
* -> One standard compound frame, followed by a compound directed frame
|
||||||
* -> <KN4CRD/P EM73> then <J1Y/P ACK>
|
* -> <KN4CRD/P EM73> then <J1Y/P ACK>
|
||||||
**/
|
**/
|
||||||
bool shouldUseStandardFrame = true;
|
if(mycallCompound || dirToCompound){
|
||||||
if(compound || dirToCompound){
|
qDebug() << "compound?" << mycallCompound << dirToCompound;
|
||||||
// Cases 1, 2, 3 all send a standard compound frame first...
|
// Cases 1, 2, 3 all send a standard compound frame first...
|
||||||
QString deCompoundMessage = QString("`%1 %2").arg(mycall).arg(mygrid);
|
QString deCompoundMessage = QString("`%1 %2").arg(mycall).arg(mygrid);
|
||||||
QString deCompoundFrame = Varicode::packCompoundMessage(deCompoundMessage, nullptr);
|
QString deCompoundFrame = Varicode::packCompoundMessage(deCompoundMessage, nullptr);
|
||||||
if(!deCompoundFrame.isEmpty()){
|
if(!deCompoundFrame.isEmpty()){
|
||||||
frames.append(deCompoundFrame);
|
frames.append({ deCompoundFrame, Varicode::JS8Call });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Followed, by a standard OR compound directed message...
|
// Followed, by a standard OR compound directed message...
|
||||||
QString dirCompoundMessage = QString("`%1%2%3").arg(dirTo).arg(dirCmd).arg(dirNum); //.replace(" ", " ");
|
QString dirCompoundMessage = QString("`%1%2%3").arg(dirTo).arg(dirCmd).arg(dirNum);
|
||||||
QString dirCompoundFrame = Varicode::packCompoundMessage(dirCompoundMessage, nullptr);
|
QString dirCompoundFrame = Varicode::packCompoundMessage(dirCompoundMessage, nullptr);
|
||||||
if(!dirCompoundFrame.isEmpty()){
|
if(!dirCompoundFrame.isEmpty()){
|
||||||
frames.append(dirCompoundFrame);
|
frames.append({ dirCompoundFrame, Varicode::JS8Call });
|
||||||
}
|
}
|
||||||
shouldUseStandardFrame = false;
|
shouldUseStandardFrame = false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(shouldUseStandardFrame) {
|
if(shouldUseStandardFrame) {
|
||||||
// otherwise, just send the standard directed frame
|
// otherwise, just send the standard directed frame
|
||||||
frames.append(frame);
|
frames.append({ frame, Varicode::JS8Call });
|
||||||
}
|
}
|
||||||
|
|
||||||
line = line.mid(n);
|
line = line.mid(n);
|
||||||
@@ -1676,21 +1852,32 @@ QStringList Varicode::buildMessageFrames(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(useDat){
|
if(useDat){
|
||||||
frames.append(frame);
|
frames.append({ frame, Varicode::JS8CallData });
|
||||||
line = line.mid(m);
|
line = line.mid(m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!frames.isEmpty()){
|
||||||
|
frames.first().second |= Varicode::JS8CallFirst;
|
||||||
|
frames.last().second |= Varicode::JS8CallLast;
|
||||||
|
}
|
||||||
|
|
||||||
return frames;
|
return frames;
|
||||||
}
|
}
|
||||||
|
|
||||||
BuildMessageFramesThread::BuildMessageFramesThread(const QString &mycall, const QString &basecall, const QString &mygrid, bool compound, const QString &selectedCall, const QString &text, QObject *parent):
|
BuildMessageFramesThread::BuildMessageFramesThread(
|
||||||
|
const QString &mycall,
|
||||||
|
//const QString &basecall,
|
||||||
|
const QString &mygrid,
|
||||||
|
//bool compound,
|
||||||
|
const QString &selectedCall,
|
||||||
|
const QString &text, QObject *parent):
|
||||||
QThread(parent),
|
QThread(parent),
|
||||||
m_mycall{mycall},
|
m_mycall{mycall},
|
||||||
m_basecall{basecall},
|
//m_basecall{basecall},
|
||||||
m_mygrid{mygrid},
|
m_mygrid{mygrid},
|
||||||
m_compound{compound},
|
//m_compound{compound},
|
||||||
m_selectedCall{selectedCall},
|
m_selectedCall{selectedCall},
|
||||||
m_text{text}
|
m_text{text}
|
||||||
{
|
{
|
||||||
@@ -1699,12 +1886,22 @@ BuildMessageFramesThread::BuildMessageFramesThread(const QString &mycall, const
|
|||||||
void BuildMessageFramesThread::run(){
|
void BuildMessageFramesThread::run(){
|
||||||
auto results = Varicode::buildMessageFrames(
|
auto results = Varicode::buildMessageFrames(
|
||||||
m_mycall,
|
m_mycall,
|
||||||
m_basecall,
|
//m_basecall,
|
||||||
m_mygrid,
|
m_mygrid,
|
||||||
m_compound,
|
//m_compound,
|
||||||
m_selectedCall,
|
m_selectedCall,
|
||||||
m_text
|
m_text
|
||||||
);
|
);
|
||||||
|
|
||||||
emit resultReady(results);
|
// TODO: jsherer - we wouldn't normally use decodedtext.h here... but it's useful for computing the actual frames transmitted.
|
||||||
|
QStringList textList;
|
||||||
|
qDebug() << "frames:";
|
||||||
|
foreach(auto frame, results){
|
||||||
|
auto dt = DecodedText(frame.first, frame.second);
|
||||||
|
qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
|
||||||
|
textList.append(dt.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto transmitText = textList.join("");
|
||||||
|
emit resultReady(transmitText, results.length());
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-15
@@ -12,6 +12,7 @@
|
|||||||
#include <QVector>
|
#include <QVector>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
||||||
|
|
||||||
class Varicode
|
class Varicode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -20,12 +21,12 @@ public:
|
|||||||
JS8Call = 0, // [000] <- any other frame of the message
|
JS8Call = 0, // [000] <- any other frame of the message
|
||||||
JS8CallFirst = 1, // [001] <- the first frame of a message
|
JS8CallFirst = 1, // [001] <- the first frame of a message
|
||||||
JS8CallLast = 2, // [010] <- the last frame of a message
|
JS8CallLast = 2, // [010] <- the last frame of a message
|
||||||
JS8CallReserved = 4, // [100] <- a reserved flag for future use...
|
JS8CallData = 4, // [100] <- raw data frame (no frame type header)
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FrameType {
|
enum FrameType {
|
||||||
FrameUnknown = 255, // [11111111] <- only used as a sentinel
|
FrameUnknown = 255, // [11111111] <- only used as a sentinel
|
||||||
FrameBeacon = 0, // [000]
|
FrameHeartbeat = 0, // [000]
|
||||||
FrameCompound = 1, // [001]
|
FrameCompound = 1, // [001]
|
||||||
FrameCompoundDirected = 2, // [010]
|
FrameCompoundDirected = 2, // [010]
|
||||||
FrameDirected = 3, // [011]
|
FrameDirected = 3, // [011]
|
||||||
@@ -39,7 +40,7 @@ public:
|
|||||||
|
|
||||||
static QString frameTypeString(quint8 type) {
|
static QString frameTypeString(quint8 type) {
|
||||||
const char* FrameTypeStrings[] = {
|
const char* FrameTypeStrings[] = {
|
||||||
"FrameBeacon",
|
"FrameHeartbeat",
|
||||||
"FrameCompound",
|
"FrameCompound",
|
||||||
"FrameCompoundDirected",
|
"FrameCompoundDirected",
|
||||||
"FrameDirected",
|
"FrameDirected",
|
||||||
@@ -62,7 +63,9 @@ public:
|
|||||||
|
|
||||||
static QMap<QString, QString> defaultHuffTable();
|
static QMap<QString, QString> defaultHuffTable();
|
||||||
static QString cqString(int number);
|
static QString cqString(int number);
|
||||||
|
static QString hbString(int number);
|
||||||
static bool startsWithCQ(QString text);
|
static bool startsWithCQ(QString text);
|
||||||
|
static bool startsWithHB(QString text);
|
||||||
static QString formatSNR(int snr);
|
static QString formatSNR(int snr);
|
||||||
static QString formatPWR(int dbm);
|
static QString formatPWR(int dbm);
|
||||||
|
|
||||||
@@ -109,6 +112,9 @@ public:
|
|||||||
static quint32 packAlphaNumeric22(QString const& value, bool isFlag);
|
static quint32 packAlphaNumeric22(QString const& value, bool isFlag);
|
||||||
static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag);
|
static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag);
|
||||||
|
|
||||||
|
static quint64 packAlphaNumeric50(QString const& value);
|
||||||
|
static QString unpackAlphaNumeric50(quint64 packed);
|
||||||
|
|
||||||
static quint32 packCallsign(QString const& value);
|
static quint32 packCallsign(QString const& value);
|
||||||
static QString unpackCallsign(quint32 value);
|
static QString unpackCallsign(quint32 value);
|
||||||
|
|
||||||
@@ -126,27 +132,29 @@ public:
|
|||||||
static bool isCommandAllowed(const QString &cmd);
|
static bool isCommandAllowed(const QString &cmd);
|
||||||
static bool isCommandBuffered(const QString &cmd);
|
static bool isCommandBuffered(const QString &cmd);
|
||||||
static int isCommandChecksumed(const QString &cmd);
|
static int isCommandChecksumed(const QString &cmd);
|
||||||
|
static bool isValidCallsign(const QString &callsign, bool *pIsCompound);
|
||||||
|
static bool isCompoundCallsign(const QString &callsign);
|
||||||
|
|
||||||
static QString packBeaconMessage(QString const &text, QString const&callsign, int *n);
|
static QString packHeartbeatMessage(QString const &text, QString const&callsign, int *n);
|
||||||
static QStringList unpackBeaconMessage(const QString &text, quint8 *pType, bool *isAlt, quint8 *pBits3);
|
static QStringList unpackHeartbeatMessage(const QString &text, quint8 *pType, bool *isAlt, quint8 *pBits3);
|
||||||
|
|
||||||
static QString packCompoundMessage(QString const &text, int *n);
|
static QString packCompoundMessage(QString const &text, int *n);
|
||||||
static QStringList unpackCompoundMessage(const QString &text, quint8 *pType, quint8 *pBits3);
|
static QStringList unpackCompoundMessage(const QString &text, quint8 *pType, quint8 *pBits3);
|
||||||
|
|
||||||
static QString packCompoundFrame(const QString &baseCallsign, const QString &fix, bool isPrefix, quint8 type, quint16 num, quint8 bits3);
|
static QString packCompoundFrame(const QString &callsign, quint8 type, quint16 num, quint8 bits3);
|
||||||
static QStringList unpackCompoundFrame(const QString &text, quint8 *pType, quint16 *pNum, quint8 *pBits3);
|
static QStringList unpackCompoundFrame(const QString &text, quint8 *pType, quint16 *pNum, quint8 *pBits3);
|
||||||
|
|
||||||
static QString packDirectedMessage(QString const& text, QString const& callsign, QString *pTo, QString * pCmd, QString *pNum, int *n);
|
static QString packDirectedMessage(QString const& text, QString const& mycall, QString *pTo, bool *pToCompound, QString * pCmd, QString *pNum, int *n);
|
||||||
static QStringList unpackDirectedMessage(QString const& text, quint8 *pType);
|
static QStringList unpackDirectedMessage(QString const& text, quint8 *pType);
|
||||||
|
|
||||||
static QString packDataMessage(QString const& text, int *n);
|
static QString packDataMessage(QString const& text, int *n);
|
||||||
static QString unpackDataMessage(QString const& text, quint8 *pType);
|
static QString unpackDataMessage(QString const& text, quint8 *pType);
|
||||||
|
|
||||||
static QStringList buildMessageFrames(
|
static QList<QPair<QString, int>> buildMessageFrames(
|
||||||
QString const& mycall,
|
QString const& mycall,
|
||||||
QString const& basecall,
|
//QString const& basecall,
|
||||||
QString const& mygrid,
|
QString const& mygrid,
|
||||||
bool compound,
|
//bool compound,
|
||||||
QString const& selectedCall,
|
QString const& selectedCall,
|
||||||
QString const& text
|
QString const& text
|
||||||
);
|
);
|
||||||
@@ -158,21 +166,21 @@ class BuildMessageFramesThread : public QThread
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
BuildMessageFramesThread(QString const& mycall,
|
BuildMessageFramesThread(QString const& mycall,
|
||||||
QString const& basecall,
|
//QString const& basecall,
|
||||||
QString const& mygrid,
|
QString const& mygrid,
|
||||||
bool compound,
|
//bool compound,
|
||||||
QString const& selectedCall,
|
QString const& selectedCall,
|
||||||
QString const& text,
|
QString const& text,
|
||||||
QObject *parent=nullptr);
|
QObject *parent=nullptr);
|
||||||
void run() override;
|
void run() override;
|
||||||
signals:
|
signals:
|
||||||
void resultReady(const QStringList s);
|
void resultReady(QString, int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_mycall;
|
QString m_mycall;
|
||||||
QString m_basecall;
|
//QString m_basecall;
|
||||||
QString m_mygrid;
|
QString m_mygrid;
|
||||||
bool m_compound;
|
//bool m_compound;
|
||||||
QString m_selectedCall;
|
QString m_selectedCall;
|
||||||
QString m_text;
|
QString m_text;
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-2
@@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>1083</width>
|
<width>1083</width>
|
||||||
<height>337</height>
|
<height>154</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>400</width>
|
<width>400</width>
|
||||||
<height>100</height>
|
<height>10</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="frameShape">
|
<property name="frameShape">
|
||||||
|
|||||||
Reference in New Issue
Block a user