Compare commits

...

96 Commits

Author SHA1 Message Date
Jordan Sherer 17416144a8 Added relay message storage and display in the call activity list 2018-12-18 21:28:31 -05:00
Jordan Sherer b8ff10fde9 Updated about messaging 2018-12-17 01:46:57 -05:00
Jordan Sherer 6c741e21b5 Removed hash messages '#' as they are now duplicated by relay '>' 2018-12-17 01:33:22 -05:00
Jordan Sherer 47eec2dc0b Added automatic ACK for relay messages 2018-12-17 01:27:41 -05:00
Jordan Sherer 6504a1f220 Bump eol and versions to 0.11.0 2018-12-17 01:04:43 -05:00
Jordan Sherer 91a2a801f9 Fixed heartbeat sub-channel configuration 2018-12-17 01:03:07 -05:00
Jordan Sherer 8c74499700 Removed unused commands 2018-12-17 00:54:54 -05:00
Jordan Sherer 51c9dd2761 Removed QRZ short message 2018-12-17 00:45:44 -05:00
Jordan Sherer dc70d53f5c Added HEARING query back into the app 2018-12-17 00:38:34 -05:00
Jordan Sherer 3c2a5f98ec Fixed #16: do not symlink js8call in usr if not using the opt install prefix 2018-12-14 21:23:06 -05:00
Jordan Sherer 5c1f890095 Fixed #13: configuration validator should require cq or callsign in cq message 2018-12-14 20:16:33 -05:00
Jordan Sherer 29f759dafe Fixed #23: idle watchdog should prevent all types of automated transmissions 2018-12-14 20:02:46 -05:00
Jordan Sherer 90858f8964 Fixed #43: space prefix should not break directed call 2018-12-13 22:22:10 -05:00
Jordan Sherer e6464e952d Removed comments 2018-12-13 22:21:37 -05:00
Jordan Sherer 186fed04e3 Fixed #41: remember pane sizes when showing/hiding 2018-12-13 09:50:02 -05:00
Jordan Sherer 6716eb771e Changed send button color while sending and label when ready 2018-12-12 22:14:45 -05:00
Jordan Sherer b8b2cf33c3 Fixed defines and % in the send button 2018-12-11 23:52:01 -05:00
Jordan Sherer 4025edfc0f Fixed rebase issues 2018-12-11 22:23:07 -05:00
Jordan Sherer c5930a0aa3 Fixed rebase issues 2018-12-11 22:14:26 -05:00
Jordan Sherer 9079d45587 Rename JS8CallExtended to JS8CallFlag 2018-12-10 23:37:22 -05:00
Jordan Sherer 223a4a2183 Updated comments to be more clear 2018-12-10 23:37:22 -05:00
Jordan Sherer 1584cf0404 Turn off turbo for now...still experimental 2018-12-10 23:37:22 -05:00
Jordan Sherer 5619824bd8 Hide turbo button for now 2018-12-10 23:37:22 -05:00
Jordan Sherer e1e2ae50e8 Simplify conditional 2018-12-10 23:35:58 -05:00
Jordan Sherer cc96daa26f Fixed button alignment 2018-12-10 23:35:58 -05:00
Jordan Sherer 5ba31d6df7 Changed frame packing so we can use one of the ibits as a turbo flag 2018-12-10 23:33:50 -05:00
Jordan Sherer 73346240e5 Fixed frame counting during turbo transmission 2018-12-10 23:30:36 -05:00
Jordan Sherer 886e678531 Fixed send button counts while in turbo 2018-12-10 23:27:21 -05:00
Jordan Sherer 526b72022e Added turbo button to the UI 2018-12-10 23:27:21 -05:00
Jordan Sherer a1864fa3f0 Configurable slots 2018-12-10 23:23:31 -05:00
Jordan Sherer b0c57029e8 Experiment with compression 2018-12-10 23:18:19 -05:00
Jordan Sherer 2d5b41d4b7 Added a waterfall indicator for turbo'd signals 2018-12-10 23:18:19 -05:00
Jordan Sherer 21004a7b28 Two-frame turbo for any message 2018-12-10 23:18:19 -05:00
Jordan Sherer 94f2f510fc Initial proof of concept of turbo button 2018-12-10 23:18:19 -05:00
Jordan Sherer b6745c9e2e Fixed #40: Force uppercase without resetting text 2018-12-10 10:18:45 -05:00
Jordan Sherer 8c81b3b83a Fixed #38: Moved Show Heartbeats menu item to the View menu 2018-12-10 09:44:16 -05:00
Jordan Sherer 9ddfec5e72 Fixed #28: band activity clear should not deselect callsign selected in call activity 2018-12-04 22:20:26 -05:00
Jordan Sherer a5f0937cbb Fixed #23: Log window should not halt transmission 2018-12-04 22:10:52 -05:00
Jordan Sherer 26f21cd70a Fixed issue with repeat messages 2018-12-03 22:42:19 -05:00
Jordan Sherer bb7e2544b5 Updated README with new links and history line items 2018-12-02 23:03:42 -05:00
Jordan Sherer 4df65585a3 Bump to v0.10.1 2018-12-01 17:22:29 -05:00
Jordan Sherer f406553a5f Fixed issues with frame counting 2018-12-01 17:17:12 -05:00
Jordan Sherer ecf14dcb5c Fixed #7: De-select callsign on save log should be visible in the settings 2018-12-01 17:03:05 -05:00
Jordan Sherer 5163a4a630 Fixed #1: automatic repeat of CQ was not transmitting when setting was not checked 2018-12-01 16:59:17 -05:00
Jordan Sherer 4af1a14961 Remove FT8 reference from ALL.txt 2018-12-01 16:51:14 -05:00
Jordan Sherer 842896d867 Restore the 'Deselect callsign after logging' setting 2018-12-01 16:47:57 -05:00
Jordan Sherer 4406e99670 Added MFSK/JS8 for logging modes 2018-11-30 17:02:14 -05:00
Jordan Sherer 79785dbef5 Fixed bug in HB auto-reply when HB was not active 2018-11-30 10:05:47 -05:00
Jordan Sherer 1d1bc254a4 Don't turn off the repeat buttons on stop button clicked, just reset them 2018-11-30 09:09:54 -05:00
Jordan Sherer 4ddccd99a1 Added a compatiblity display for old heartbeat acks 2018-11-29 22:53:56 -05:00
Jordan Sherer dd6f50a5a3 Bump version and EOL 2018-11-29 22:51:19 -05:00
Jordan Sherer 55c365b834 Added heartbeat and CQ to control menu 2018-11-29 22:43:15 -05:00
Jordan Sherer b55f8ba5c5 Added option for displaying/hiding heartbeats and acks 2018-11-29 22:34:39 -05:00
Jordan Sherer fd77e5440f Keep configuration option for heartbeat channelization 2018-11-29 22:19:17 -05:00
Jordan Sherer 19cb0b859d SELCALL checked should disable repeat transmissions 2018-11-29 21:53:03 -05:00
Jordan Sherer 3d3be02830 Countdown for HB and CQ. Escape key stops CQ and resets HB timer 2018-11-28 22:53:18 -05:00
Jordan Sherer 55f04d3cd7 Fixed padding of configuration behavior panel 2018-11-28 16:42:09 -05:00
Jordan Sherer 693eec8b4b Rename do not repeat 2018-11-27 23:25:40 -05:00
Jordan Sherer 9244ac08c6 Hide heartbeat and acks if we have HB turned off 2018-11-27 23:21:16 -05:00
Jordan Sherer 8004c51ed2 Hide configuration for heartbeat. 2018-11-27 23:16:02 -05:00
Jordan Sherer 52b67a5609 HB and CQ repeat logic 2018-11-27 23:04:11 -05:00
Jordan Sherer 3e7c64e994 Proper active/inactive flags for HB 2018-11-26 22:40:34 -05:00
Jordan Sherer d9d3e6fba3 Added active/inactive flag and restructuring heartbeat 2018-11-25 22:12:54 -05:00
Jordan Sherer 09cea086c7 Added fullscreen toggle 2018-11-22 10:37:38 -05:00
Jordan Sherer a013e79eff Reordering varicode commands to make it easier to spot which numbers are available 2018-11-20 10:09:07 -05:00
Jordan Sherer a3e004375e Added deselect callsign after logging as an option instead of forced 2018-11-20 09:50:53 -05:00
Jordan Sherer f018a622ce Removed printing of ALLCALL messages that were not freetext in the RX window 2018-11-19 23:02:59 -05:00
Jordan Sherer 565c031b28 Added add/remove group from callsign list and it propagate to the settings 2018-11-19 22:36:28 -05:00
Jordan Sherer d88d8aa440 Removed clear menu item icons 2018-11-19 22:36:10 -05:00
Jordan Sherer 3a59599253 Fix SELCALL and HB menu items toggle vs click 2018-11-16 15:36:02 -05:00
Jordan Sherer 22e4b0891e Bump eol 2018-11-15 22:09:03 -05:00
Jordan Sherer 8c564b6637 Added control menu 2018-11-15 22:06:52 -05:00
Jordan Sherer 97763ed82d Bump to 0.9 2018-11-15 21:57:20 -05:00
Jordan Sherer a7849c5b72 Added push button bold style for colorblindness 2018-11-15 21:57:04 -05:00
Jordan Sherer 04394273dd Added notification for CQ messages 2018-11-15 15:03:05 -05:00
Jordan Sherer 1052dd3f9f Added macro expansion in typed message text 2018-11-14 22:48:31 -05:00
Jordan Sherer 78ed799a8b Updated configuration panel to be more flexible (scroll areas) 2018-11-14 22:03:45 -05:00
Jordan Sherer c0d08f87b6 Added keyboard shortcuts to the basic Show actions. Added show action to disable tooltips 2018-11-13 12:35:39 -05:00
Jordan Sherer f92b3db5ea Added ability to add an arbitrary station to the heard list manually 2018-11-12 16:51:51 -05:00
Jordan Sherer cebed44ccd User Interface Tweaks:
* Changed Window Menu to View Menu
* Added Show Clock to View Menu
* Changed minimum sizing for better fit on smaller screens
* Reordered Clock and Date for Clock Priority
2018-11-12 16:34:31 -05:00
Jordan Sherer d47d88681b Updated dependencies list 2018-11-11 15:06:45 -05:00
Jordan Sherer 1be0ee4f4f Added a reference to dependency installation 2018-11-11 14:58:23 -05:00
Jordan Sherer 43d8986e0a Tweaking window sizes 2018-11-08 17:11:25 -05:00
Jordan Sherer fd69dce0ae Fixed word wrapping of non-breaking space words by only replacing double spaces 2018-11-06 23:06:05 -05:00
Jordan Sherer b2fb3f31ac Added azimuth to the distance column 2018-11-06 17:28:21 -05:00
Jordan Sherer db704858e2 Merge branch 'ft8call-develop' of bitbucket.org:widefido/js8call into ft8call-develop 2018-11-05 21:36:13 -05:00
Jordan Sherer 1d11f0f8ba Fixed word wrapping with no break spaces 2018-11-05 21:13:16 -05:00
Jordan Sherer b6bc50a8e1 Fixed QAction for older Qt versions 2018-11-05 17:00:59 -05:00
Jordan Sherer 5addf8f61f Fixed bug with space collapsing in displayTextForFreq 2018-11-05 16:51:24 -05:00
Jordan Sherer 367966f5e6 Bump to v0.8.3 2018-11-05 16:47:09 -05:00
Jordan Sherer caaaa957b6 Fixed OSX issue with menuBar menus that have sub-menues that aren't populated at construction, but when the menu is aboutToShow 2018-11-05 16:00:12 -05:00
Jordan Sherer c440d4c143 Added TDELTA macro variable 2018-11-05 11:35:37 -05:00
Jordan Sherer 740c0b4c04 Fixed call activity with empty rows 2018-11-04 14:57:44 -05:00
Jordan Sherer f5ce9f0e30 Added TU short command 2018-11-03 22:38:27 -04:00
Jordan Sherer 0a6ec136f9 Fixed macro expansion for auto-reply messages QTC and QTH 2018-11-03 22:20:49 -04:00
Jordan Sherer d5e1f2822d Fixed more issues with compressed data decoding and invalid frames 2018-11-03 22:14:42 -04:00
28 changed files with 5445 additions and 4088 deletions
+7 -5
View File
@@ -1272,12 +1272,14 @@ if (NOT WIN32 AND NOT APPLE)
#COMPONENT runtime #COMPONENT runtime
) )
execute_process(COMMAND ln -s /opt/js8call/bin/js8call ljs8call) IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/opt/js8call")
execute_process(COMMAND ln -s /opt/js8call/bin/js8call ljs8call)
install(FILES install(FILES
${CMAKE_BINARY_DIR}/ljs8call DESTINATION /usr/bin/ RENAME js8call ${CMAKE_BINARY_DIR}/ljs8call DESTINATION /usr/bin/ RENAME js8call
#COMPONENT runtime #COMPONENT runtime
) )
endif()
endif (NOT WIN32 AND NOT APPLE) endif (NOT WIN32 AND NOT APPLE)
+97 -36
View File
@@ -463,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();
@@ -517,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
@@ -638,7 +642,7 @@ 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_;
@@ -769,7 +773,7 @@ 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_;}
@@ -810,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;}
@@ -940,6 +945,20 @@ QSet<QString> Configuration::my_groups() const {
return QSet<QString>::fromList(m_->my_groups_); 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();
@@ -1009,6 +1028,12 @@ namespace
} }
} }
template <typename T> void setUppercase(T* t){
auto f = t->font();
f.setCapitalization(QFont::AllUppercase);
t->setFont(f);
}
Configuration::impl::impl (Configuration * self, QDir const& temp_directory, Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
QSettings * settings, QWidget * parent) QSettings * settings, QWidget * parent)
: QDialog {parent} : QDialog {parent}
@@ -1042,6 +1067,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 ??? ###
{ {
@@ -1117,6 +1143,16 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
ui_->qth_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this}); ui_->qth_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->reply_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this}); ui_->reply_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->cq_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this}); ui_->cq_message_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->groups_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
setUppercase(ui_->callsign_line_edit);
setUppercase(ui_->grid_line_edit);
setUppercase(ui_->add_macro_line_edit);
setUppercase(ui_->station_message_line_edit);
setUppercase(ui_->qth_message_line_edit);
setUppercase(ui_->reply_message_line_edit);
setUppercase(ui_->cq_message_line_edit);
setUppercase(ui_->groups_line_edit);
ui_->udp_server_port_spin_box->setMinimum (1); ui_->udp_server_port_spin_box->setMinimum (1);
ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ()); ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
@@ -1331,6 +1367,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_);
@@ -1346,7 +1383,7 @@ 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_);
@@ -1430,7 +1467,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);
} }
@@ -1438,7 +1475,9 @@ 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 ();
@@ -1533,6 +1572,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 ();
@@ -1653,7 +1693,7 @@ 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 ();
@@ -1736,6 +1776,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_);
@@ -1787,7 +1828,7 @@ 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_);
@@ -1880,7 +1921,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);
@@ -1889,7 +1931,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);
@@ -1940,7 +1983,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 ()
@@ -1977,7 +2022,7 @@ QStringList splitGroups(QString groupsString, bool filter){
bool Configuration::impl::validate () bool Configuration::impl::validate ()
{ {
auto callsign = ui_->callsign_line_edit->text().trimmed(); auto callsign = ui_->callsign_line_edit->text().toUpper().trimmed();
if(!Varicode::isValidCallsign(callsign, nullptr) || callsign.startsWith("@")){ if(!Varicode::isValidCallsign(callsign, nullptr) || callsign.startsWith("@")){
MessageBox::critical_message (this, tr ("The callsign format you provided is not supported")); MessageBox::critical_message (this, tr ("The callsign format you provided is not supported"));
return false; return false;
@@ -1990,6 +2035,12 @@ bool Configuration::impl::validate ()
} }
} }
auto cq = ui_->cq_message_line_edit->text().toUpper().trimmed();
if(!cq.isEmpty() && !(cq.startsWith("CQ") || cq.contains(callsign))){
MessageBox::critical_message (this, QString("The CQ message format is invalid. It must either start with \"CQ\" or contain your callsign."));
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 ())
{ {
@@ -2238,12 +2289,10 @@ void Configuration::impl::accept ()
Q_ASSERT (audio_output_channel_ <= AudioDevice::Both); Q_ASSERT (audio_output_channel_ <= AudioDevice::Both);
auto_switch_bands_ = ui_->auto_switch_bands_check_box->isChecked(); auto_switch_bands_ = ui_->auto_switch_bands_check_box->isChecked();
my_callsign_ = ui_->callsign_line_edit->text (); my_callsign_ = ui_->callsign_line_edit->text ().toUpper();
my_grid_ = ui_->grid_line_edit->text (); my_grid_ = ui_->grid_line_edit->text ().toUpper();
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); 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();
@@ -2268,7 +2317,7 @@ 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 ();
@@ -2277,6 +2326,7 @@ void Configuration::impl::accept ()
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 ();
@@ -2668,43 +2718,23 @@ void Configuration::impl::on_sound_output_combo_box_currentTextChanged (QString
void Configuration::impl::on_station_message_line_edit_textChanged(QString const &text) void Configuration::impl::on_station_message_line_edit_textChanged(QString const &text)
{ {
QString upper = text.toUpper();
if(text != upper){
ui_->station_message_line_edit->setText (upper);
}
} }
void Configuration::impl::on_groups_line_edit_textChanged(QString const &text) 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();
if(text != upper){
ui_->qth_message_line_edit->setText (upper);
}
} }
void Configuration::impl::on_cq_message_line_edit_textChanged(QString const &text) void Configuration::impl::on_cq_message_line_edit_textChanged(QString const &text)
{ {
QString upper = text.toUpper();
if(text != upper){
ui_->cq_message_line_edit->setText (upper);
}
} }
void Configuration::impl::on_reply_message_line_edit_textChanged(QString const &text) void Configuration::impl::on_reply_message_line_edit_textChanged(QString const &text)
{ {
QString upper = text.toUpper();
if(text != upper){
ui_->reply_message_line_edit->setText (upper);
}
} }
void Configuration::impl::on_add_macro_line_edit_editingFinished () void Configuration::impl::on_add_macro_line_edit_editingFinished ()
@@ -2763,7 +2793,7 @@ void Configuration::impl::on_add_macro_push_button_clicked (bool /* checked */)
{ {
auto index = next_macros_.index (next_macros_.rowCount () - 1); auto index = next_macros_.index (next_macros_.rowCount () - 1);
ui_->macros_list_view->setCurrentIndex (index); ui_->macros_list_view->setCurrentIndex (index);
next_macros_.setData (index, ui_->add_macro_line_edit->text ()); next_macros_.setData (index, ui_->add_macro_line_edit->text ().toUpper());
ui_->add_macro_line_edit->clear (); ui_->add_macro_line_edit->clear ();
} }
} }
@@ -2945,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)"
+4 -1
View File
@@ -99,6 +99,8 @@ public:
QString my_grid () const; QString my_grid () const;
QString my_station () const; QString my_station () const;
QSet<QString> my_groups() 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;
@@ -131,7 +133,7 @@ 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;
@@ -180,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;
+3247 -2851
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -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
+7 -1
View File
@@ -10,10 +10,12 @@ JS8Call is an experiment to test the feasibility of a digital mode with the robu
* For release announcements and discussion, join the JS8Call mailing list here: https://groups.io/g/js8call * For release announcements and discussion, join the JS8Call mailing list here: https://groups.io/g/js8call
* Documentation is available here: https://docs.google.com/document/d/159S4wqMUVdMA7qBgaSWmU-iDI4C9wd4CuWnetN68O9U/edit?pli=1#heading=h.kfnyge37yfr
# Notice # Notice
JS8Call is a derivative of the WSJT-X application, restructured and redesigned for message passing using FT8 modulation. It is not supported by nor endorsed by the WSJT-X development group. While the WSJT-X group maintains copyright over the original work and code, JS8Call is a derivative work licensed under and in accordance with the terms of the GPLv3 license. The source code modifications are public and can be found in this repository: https://bitbucket.org/widefido/wsjtx/ JS8Call is a derivative of the WSJT-X application, restructured and redesigned for message passing using FT8 modulation. It is not supported by nor endorsed by the WSJT-X development group. While the WSJT-X group maintains copyright over the original work and code, JS8Call is a derivative work licensed under and in accordance with the terms of the GPLv3 license. The source code modifications are public and can be found in this repository: https://bitbucket.org/widefido/js8call/
# History # History
@@ -33,3 +35,7 @@ JS8Call is a derivative of the WSJT-X application, restructured and redesigned f
* August 12, 2018 - Version 0.4 released - (“leaked” on QRZ) - 500 testers * August 12, 2018 - Version 0.4 released - (“leaked” on QRZ) - 500 testers
* September 2, 2018 - Version 0.5 released - 3000 testers * September 2, 2018 - Version 0.5 released - 3000 testers
* September 14, 2018 - Version 0.6 released - 5000 testers * September 14, 2018 - Version 0.6 released - 5000 testers
* October 8, 2018 - Version 0.7 released - 6000 testers, name changed to JS8 & JS8Call
* October 31, 2018 - Version 0.8 released - ~7000 testers
* November 15, 2018 - Version 0.9 released - ~7500 testers
* November 30, 2018 - Version 0.10 released - ~7800 testers
+2 -2
View File
@@ -1,6 +1,6 @@
# Version number components # Version number components
set (WSJTX_VERSION_MAJOR 0) set (WSJTX_VERSION_MAJOR 0)
set (WSJTX_VERSION_MINOR 8) set (WSJTX_VERSION_MINOR 11)
set (WSJTX_VERSION_PATCH 2) set (WSJTX_VERSION_PATCH 0)
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
+3 -3
View File
@@ -31,7 +31,7 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
"community.<br /><br />" "community.<br /><br />"
"JS8Call stands on the shoulder of giants...the takeoff angle " "JS8Call stands on the shoulder of giants...the takeoff angle "
"is better up there.<br /><br />" "is better up there.<br /><br />"
"A special thanks goes out to the JS8Call development team:<br/><br/><strong>" "A special thanks goes out to:<br/><br/><strong>"
"KC9QNE, " "KC9QNE, "
"KI6SSI, " "KI6SSI, "
"K0OG, " "K0OG, "
@@ -41,8 +41,8 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
"OH8STN, " "OH8STN, "
"VA3OSO, " "VA3OSO, "
"VK1MIC, " "VK1MIC, "
"W0FW,</strong><br/><br/>and the many other amateur radio operators who have given " "W0FW,</strong><br/><br/>and the many other amateur radio operators who have helped<br/>"
"JS8Call a chance."); "bring JS8Call into the world.");
} }
CAboutDlg::~CAboutDlg() CAboutDlg::~CAboutDlg()
+4 -9
View File
@@ -126,7 +126,7 @@ bool DecodedText::tryUnpackHeartbeat(){
// Heartbeat Alt Type // Heartbeat Alt Type
// --------------- // ---------------
// 1 0 BCN // 1 0 HB
// 1 1 CQ // 1 1 CQ
isHeartbeat_ = true; isHeartbeat_ = true;
isAlt_ = isAlt; isAlt_ = isAlt;
@@ -140,7 +140,7 @@ bool DecodedText::tryUnpackHeartbeat(){
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) : "HEARTBEAT").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;
} }
@@ -221,19 +221,14 @@ bool DecodedText::tryUnpackData(){
return false; return false;
} }
if((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData){ QString data = Varicode::unpackDataMessage(m);
return false;
}
quint8 type = Varicode::FrameUnknown;
QString data = Varicode::unpackDataMessage(m, &type);
if(data.isEmpty()){ if(data.isEmpty()){
return false; return false;
} }
message_ = data; message_ = data;
frameType_ = type; frameType_ = Varicode::FrameData;
return true; return true;
} }
+6
View File
@@ -137,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);
+49 -49
View File
@@ -48,50 +48,50 @@ subroutine foxgen()
do n=1,nslots do n=1,nslots
i3b=i3bit(n) i3b=i3bit(n)
if(i3b.eq.0) then !if(i3b.eq.0) then
msg=cmsg(n)(1:22) !Standard FT8 message msg=cmsg(n)(1:12) !Standard FT8 message
else !else
i1=index(cmsg(n),' ') !Special Fox message ! i1=index(cmsg(n),' ') !Special Fox message
i2=index(cmsg(n),';') ! i2=index(cmsg(n),';')
i3=index(cmsg(n),'<') ! i3=index(cmsg(n),'<')
i4=index(cmsg(n),'>') ! i4=index(cmsg(n),'>')
msg=cmsg(n)(1:i1)//cmsg(n)(i2+1:i3-2)//' ' ! msg=cmsg(n)(1:i1)//cmsg(n)(i2+1:i3-2)//' '
read(cmsg(n)(i4+2:i4+4),*) irpt ! read(cmsg(n)(i4+2:i4+4),*) irpt
endif !endif
call genft8(msg,mygrid,bcontest,0,msgsent,msgbits,itone) call genft8(msg,mygrid,bcontest,i3b,msgsent,msgbits,itone)
! print*,'Foxgen:',n,cmsg(n),msgsent ! print*,'Foxgen:',n,cmsg(n),msgsent
if(i3b.eq.1) then !! if(i3b.eq.1) then
icrc10=crc10(c_loc(mycall),12) !! icrc10=crc10(c_loc(mycall),12)
nrpt=irpt+30 !! nrpt=irpt+30
write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,0 !! write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,0
1001 format(56b1.1,b10.10,b6.6,b3.3,b12.12) !! 1001 format(56b1.1,b10.10,b6.6,b3.3,b12.12)
read(cbits,1002) msgbits !! read(cbits,1002) msgbits
1002 format(87i1) !! 1002 format(87i1)
!!
cb88=cbits//'0' !! cb88=cbits//'0'
read(cb88,1003) i1Msg8BitBytes(1:11) !! read(cb88,1003) i1Msg8BitBytes(1:11)
1003 format(11b8) !! 1003 format(11b8)
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, 41) ! TODO: jsherer - could change the crc here
!!
write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,icrc12 !! write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,icrc12
read(cbits,1002) msgbits !! read(cbits,1002) msgbits
!!
call encode174(msgbits,codeword) !Encode the test message !! call encode174(msgbits,codeword) !Encode the test message
!!
! Message structure: S7 D29 S7 D29 S7 !! ! Message structure: S7 D29 S7 D29 S7
itone(1:7)=icos7 !! itone(1:7)=icos7
itone(36+1:36+7)=icos7 !! itone(36+1:36+7)=icos7
itone(NN-6:NN)=icos7 !! itone(NN-6:NN)=icos7
k=7 !! k=7
do j=1,ND !! do j=1,ND
i=3*j -2 !! i=3*j -2
k=k+1 !! k=k+1
if(j.eq.30) k=k+7 !! if(j.eq.30) k=k+7
itone(k)=codeword(i)*4 + codeword(i+1)*2 + codeword(i+2) !! itone(k)=codeword(i)*4 + codeword(i+1)*2 + codeword(i+2)
enddo !! enddo
endif !! endif
! Make copies of itone() and msgbits() for ft8sim ! Make copies of itone() and msgbits() for ft8sim
itone2=itone itone2=itone
@@ -117,13 +117,13 @@ subroutine foxgen()
! call plotspec(1,wave) !Plot the spectrum ! call plotspec(1,wave) !Plot the spectrum
! Apply compression ! Apply compression
! rms=sqrt(dot_product(wave,wave)/kz) rms=sqrt(dot_product(wave,wave)/kz)
! wave=wave/rms wave=wave/rms
! do i=1,NWAVE do i=1,NWAVE
! wave(i)=h1(wave(i)) wave(i)=h1(wave(i))
! enddo enddo
! peak2=maxval(abs(wave)) peak2=maxval(abs(wave))
! wave=wave/peak2 wave=wave/peak2
! call plotspec(2,wave) !Plot the spectrum ! call plotspec(2,wave) !Plot the spectrum
+9 -20
View File
@@ -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,22 +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("JS8",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("JS8",Qt::CaseInsensitive)==0) ||
(q.mode.compare("FT8",Qt::CaseInsensitive)==0))
)
|| (mode.compare(q.mode,Qt::CaseInsensitive)==0)
|| (mode=="")
|| (q.mode=="")
)
return true; return true;
} }
} }
@@ -176,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
@@ -186,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
View File
@@ -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;
+5 -6
View File
@@ -50,8 +50,8 @@ void LogBook::_setAlreadyWorkedFromLog()
} }
} }
bool LogBook::hasWorkedBefore(const QString &call, const QString &band, const QString &mode){ bool LogBook::hasWorkedBefore(const QString &call, const QString &band){
return _log.match(call, band, mode); return _log.match(call, band);
} }
void LogBook::match(/*in*/const QString call, void LogBook::match(/*in*/const QString call,
@@ -61,9 +61,8 @@ void LogBook::match(/*in*/const QString call,
{ {
if (call.length() > 0) if (call.length() > 0)
{ {
QString currentMode = ""; // match any mode
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);
if (countryName.length() > 0) // country was found if (countryName.length() > 0) // country was found
@@ -76,9 +75,9 @@ void LogBook::match(/*in*/const QString call,
} }
} }
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)
{ {
_log.add(call,band,mode,date); _log.add(call,band,mode,submode,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 -2
View File
@@ -20,12 +20,12 @@ class LogBook
{ {
public: public:
void init(); void init();
bool hasWorkedBefore(const QString &call, const QString &band, const QString &mode); 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;
+10 -6
View File
@@ -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().toUpper(); hisCall=ui->call->text().toUpper();
hisGrid=ui->grid->text().toUpper(); hisGrid=ui->grid->text().toUpper();
mode=ui->mode->text().toUpper(); 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();
} }
+1 -1
View File
@@ -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
+3
View File
@@ -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>
+984 -277
View File
File diff suppressed because it is too large Load Diff
+48 -13
View File
@@ -130,6 +130,7 @@ 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);
@@ -152,6 +153,7 @@ public slots:
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); bool ensureKeyNotStuck(QString const& text);
bool ensureNotIdle();
void createMessage(QString const& text); void createMessage(QString const& text);
void createMessageTransmitQueue(QString const& text); void createMessageTransmitQueue(QString const& text);
void resetMessageTransmitQueue(); void resetMessageTransmitQueue();
@@ -170,8 +172,16 @@ 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_Band_Heartbeats_and_ACKs_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);
void on_actionShow_Waterfall_Controls_triggered(bool checked); void on_actionShow_Waterfall_Controls_triggered(bool checked);
@@ -185,6 +195,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();
@@ -265,6 +276,14 @@ 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_snrMacroButton_clicked();
@@ -302,12 +321,8 @@ private slots:
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 scheduleHeartbeat(bool first=false); void checkRepeat();
void pauseHeartbeat(); QString calculateDistance(QString const& grid, int *pDistance=nullptr, int *pAzimuth=nullptr);
void unpauseHeartbeat();
void checkHeartbeat();
void prepareHeartbeat();
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();
@@ -318,10 +333,9 @@ 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_heartbeatButton_clicked(); void on_turboButton_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
@@ -342,6 +356,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);
@@ -648,7 +670,7 @@ private:
QTimer minuteTimer; QTimer minuteTimer;
QTimer splashTimer; QTimer splashTimer;
QTimer p1Timer; QTimer p1Timer;
QTimer heartbeatTimer; QTimer repeatTimer;
QString m_path; QString m_path;
QString m_baseCall; QString m_baseCall;
@@ -707,6 +729,7 @@ private:
QString text; QString text;
QString extra; QString extra;
float tdrift; float tdrift;
QString relayPath;
}; };
struct ActivityDetail struct ActivityDetail
@@ -731,6 +754,10 @@ private:
QList<ActivityDetail> msgs; QList<ActivityDetail> msgs;
}; };
int m_bandActivityWidth;
int m_callActivityWidth;
int m_textActivityWidth;
int m_waterfallHeight;
bool m_bandActivityWasVisible; bool m_bandActivityWasVisible;
bool m_rxDirty; bool m_rxDirty;
bool m_rxDisplayDirty; bool m_rxDisplayDirty;
@@ -790,6 +817,8 @@ private:
QQueue<QString> m_txHeartbeatQueue; // ping 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, QList<CommandDetail>> m_rxCallsignCommandQueue; // call -> [cmd, ...]
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
@@ -818,9 +847,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_nextHeartbeatQueued = false; bool m_hbHidden;
bool m_nextHeartPaused = false; int m_hbInterval;
int m_cqInterval;
QDateTime m_nextHeartbeat; QDateTime m_nextHeartbeat;
QDateTime m_nextCQ;
QDateTime m_dateTimeQSOOn; QDateTime m_dateTimeQSOOn;
QDateTime m_dateTimeLastTX; QDateTime m_dateTimeLastTX;
@@ -847,7 +878,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;
@@ -886,6 +916,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);
@@ -934,6 +965,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);
+768 -716
View File
File diff suppressed because it is too large Load Diff
+31
View File
@@ -27,6 +27,7 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
m_plot2dGain {0}, m_plot2dGain {0},
m_plot2dZero {0}, m_plot2dZero {0},
m_nSubMode {0}, m_nSubMode {0},
m_turbo {false},
m_Running {false}, m_Running {false},
m_paintEventBusy {false}, m_paintEventBusy {false},
m_fftBinWidth {1500.0/2048.0}, m_fftBinWidth {1500.0/2048.0},
@@ -587,6 +588,9 @@ void CPlotter::DrawOverlay() //DrawOverlay()
if(m_mode=="FT8"){ if(m_mode=="FT8"){
int fwidth=XfromFreq(m_rxFreq+bw)-XfromFreq(m_rxFreq); int fwidth=XfromFreq(m_rxFreq+bw)-XfromFreq(m_rxFreq);
#if TEST_FOX_WAVE_GEN
int offset=XfromFreq(m_rxFreq+bw+10)-XfromFreq(m_rxFreq+bw);
#endif
QPainter overPainter(&m_DialOverlayPixmap); QPainter overPainter(&m_DialOverlayPixmap);
overPainter.initFrom(this); overPainter.initFrom(this);
overPainter.setCompositionMode(QPainter::CompositionMode_Source); overPainter.setCompositionMode(QPainter::CompositionMode_Source);
@@ -595,10 +599,22 @@ void CPlotter::DrawOverlay() //DrawOverlay()
overPainter.setPen(thinRed); overPainter.setPen(thinRed);
overPainter.drawLine(0, 30, 0, m_h); overPainter.drawLine(0, 30, 0, m_h);
overPainter.drawLine(fwidth+1, 30, fwidth+1, m_h); overPainter.drawLine(fwidth+1, 30, fwidth+1, m_h);
#if TEST_FOX_WAVE_GEN
if(m_turbo){
overPainter.drawLine(offset+fwidth+1, 30, offset+fwidth+1, m_h);
overPainter.drawLine(offset+2*fwidth+1, 30, offset+2*fwidth+1, m_h);
}
#endif
overPainter.setPen(penRed); overPainter.setPen(penRed);
overPainter.drawLine(0, 26, fwidth, 26); overPainter.drawLine(0, 26, fwidth, 26);
overPainter.drawLine(0, 28, fwidth, 28); overPainter.drawLine(0, 28, fwidth, 28);
#if TEST_FOX_WAVE_GEN
if(m_turbo){
overPainter.drawLine(offset+fwidth, 26, offset+2*fwidth, 26);
overPainter.drawLine(offset+fwidth, 28, offset+2*fwidth, 28);
}
#endif
QPainter hoverPainter(&m_HoverOverlayPixmap); QPainter hoverPainter(&m_HoverOverlayPixmap);
hoverPainter.initFrom(this); hoverPainter.initFrom(this);
@@ -607,6 +623,12 @@ void CPlotter::DrawOverlay() //DrawOverlay()
hoverPainter.setPen(QPen(Qt::white)); hoverPainter.setPen(QPen(Qt::white));
hoverPainter.drawLine(0, 30, 0, m_h); hoverPainter.drawLine(0, 30, 0, m_h);
hoverPainter.drawLine(fwidth+1, 30, fwidth+1, m_h); hoverPainter.drawLine(fwidth+1, 30, fwidth+1, m_h);
#if TEST_FOX_WAVE_GEN
if(m_turbo){
hoverPainter.drawLine(offset+fwidth+1, 30, offset+fwidth+1, m_h);
hoverPainter.drawLine(offset+2*fwidth+1, 30, offset+2*fwidth+1, m_h);
}
#endif
#if DRAW_FREQ_OVERLAY #if DRAW_FREQ_OVERLAY
int f = FreqfromX(m_lastMouseX); int f = FreqfromX(m_lastMouseX);
@@ -865,6 +887,15 @@ void CPlotter::setDialFreq(double d)
void CPlotter::setRxBand(QString band) void CPlotter::setRxBand(QString band)
{ {
m_rxBand=band; m_rxBand=band;
DrawOverlay();
update();
}
void CPlotter::setTurbo(bool turbo)
{
m_turbo=turbo;
DrawOverlay();
update();
} }
void CPlotter::setFlatten(bool b1, bool b2) void CPlotter::setFlatten(bool b1, bool b2)
+2
View File
@@ -81,6 +81,7 @@ public:
void setFlatten(bool b1, bool b2); void setFlatten(bool b1, bool b2);
void setTol(int n); void setTol(int n);
void setRxBand(QString band); void setRxBand(QString band);
void setTurbo(bool turbo);
void setReference(bool b) {m_bReference = b;} void setReference(bool b) {m_bReference = b;}
bool Reference() const {return m_bReference;} bool Reference() const {return m_bReference;}
void drawRed(int ia, int ib, float swide[]); void drawRed(int ia, int ib, float swide[]);
@@ -147,6 +148,7 @@ private:
QString m_rxBand; QString m_rxBand;
QString m_redFile; QString m_redFile;
bool m_turbo;
bool m_Running; bool m_Running;
bool m_paintEventBusy; bool m_paintEventBusy;
bool m_dataFromDisk; bool m_dataFromDisk;
+115 -68
View File
@@ -27,6 +27,7 @@
#include "varicode.h" #include "varicode.h"
#include "jsc.h" #include "jsc.h"
#include "decodedtext.h"
#include <cmath> #include <cmath>
@@ -54,25 +55,30 @@ QMap<QString, int> directed_cmds = {
{" QTC?", 2 }, // query station message {" QTC?", 2 }, // query station message
{"&", 2 }, // compat {"&", 2 }, // compat
{" HEARING?", 3 }, // query station calls heard
{"$", 3 }, // compat
{" GRID?", 4 }, // query grid {" GRID?", 4 }, // query grid
{"^", 4 }, // compat {"^", 4 }, // compat
{">", 5 }, // relay message
{" STATUS?", 6 }, // query idle message {" STATUS?", 6 }, // query idle message
{"*", 6 }, // compat {"*", 6 }, // compat
{">", 5 }, // relay message //{"!", 7 }, // unused
{"#", 8 }, // all or nothing message //{"#", 8 }, // unused
//{"!", 7 }, // alert message {" TU", 9 }, // thank you
//{"$", 3 }, // query station(s) heard
//{"=", 9 }, // unused
{" ACTIVE", 10 }, // i have been active in the past 10 minutes {" ACTIVE", 10 }, // i am active
{" IDLE", 11 }, // i have not been active in the past 10 minutes {" IDLE", 11 }, // i am idle
{" HEARTBEAT", -1 }, // this is my ping (unused except for faux processing of pings as directed commands) {" HB", -1 }, // this is my heartbeat (unused except for faux processing of HBs as directed commands)
{" HEARTBEAT ACK", 12 }, // i acknowledge your ping at this SNR
{" HEARTBEAT REQ", 13 }, // can you transmit a ping to callsign? // {" ", 12 }, // unused
{" QUERY", 13 }, // can you transmit a ping to callsign?
{" APRS:", 14 }, // send an aprs packet {" APRS:", 14 }, // send an aprs packet
@@ -86,42 +92,42 @@ QMap<QString, int> directed_cmds = {
{" 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
{" QRZ?", 24 }, // who is calling me // {" ", 24 }, // unused
{" SNR", 25 }, // seen a station at the provided snr {" SNR", 25 }, // seen a station at the provided snr
{" NO", 26 }, // negative confirm {" NO", 26 }, // negative confirm
{" YES", 27 }, // confirm {" YES", 27 }, // confirm
{" 73", 28 }, // best regards, end of contact {" 73", 28 }, // best regards, end of contact
{" ACK", 29 }, // acknowledge {" ACK", 29 }, // acknowledge
{" AGN?", 30 }, // repeat message {" AGN?", 30 }, // repeat message
{" ", 31 }, // send freetext {" ", 31 }, // send freetext (weird artifact)
{" ", 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,*/ 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, 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?(?:HEARTBEAT (ACK|REQ)|AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|QRZ[?]|SNR[?]|QTC[?]|QTH[?]|GRID[?]|STATUS[?]|(?:(?:ACK|73|YES|NO|SNR|QSL|RR|SK|FB|QTH|QTC|GRID|ACTIVE|IDLE)(?=[ ]|$))|[?*^&@#> ]))?"); QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|QSL[?]|HW CPY[?]|APRS[:]|SNR[?]|QTC[?]|QTH[?]|GRID[?]|STATUS[?]|HEARING[?]|(?:(?: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|HEARTBEAT 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 heartbeat_re(R"(^\s*(?<type>CQCQCQ|CQ QRPP?|CQ DX|CQ TEST|CQ( CQ){0,2}|HEARTBEAT)(?:\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 +
@@ -203,6 +209,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
@@ -289,6 +301,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)){
@@ -298,6 +317,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();
@@ -991,7 +1019,7 @@ quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
// [1][X][6] // [1][X][6]
// X = 0 == SNR // X = 0 == SNR
// X = 1 == ACK // X = 1 == ACK
value = ((1 << 1) | (int)(cmdStr == " HEARTBEAT 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 {
@@ -1009,7 +1037,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[" HEARTBEAT ACK"]; cmd = directed_cmds[" ACK"];
} }
return cmd; return cmd;
} else { } else {
@@ -1118,7 +1146,8 @@ bool Varicode::isCompoundCallsign(const QString &callsign){
// CQCQCQ EM73 // CQCQCQ EM73
// CQ DX EM73 // CQ DX EM73
// CQ QRP EM73 // CQ QRP EM73
// HEARTBEAT EM73 // HB ACTIVE EM73
// HB IDLE EM73
QString Varicode::packHeartbeatMessage(QString const &text, const QString &callsign, int *n){ QString Varicode::packHeartbeatMessage(QString const &text, const QString &callsign, int *n){
QString frame; QString frame;
@@ -1132,8 +1161,8 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
// Heartbeat Alt Type // Heartbeat Alt Type
// --------------- // ---------------
// 1 0 HEARTBEAT // 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");
@@ -1148,13 +1177,14 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
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, Varicode::FrameHeartbeat, packed_extra, cqNumber);
frame = packCompoundFrame(callsign, FrameHeartbeat, packed_extra, cqNumber);
if(frame.isEmpty()){ if(frame.isEmpty()){
if(n) *n = 0; if(n) *n = 0;
return frame; return frame;
@@ -1165,12 +1195,12 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
} }
QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType, bool * isAlt, quint8 * pBits3){ QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType, bool * isAlt, quint8 * pBits3){
quint8 type = FrameHeartbeat; quint8 type = Varicode::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 != FrameHeartbeat){ if(unpacked.isEmpty() || type != Varicode::FrameHeartbeat){
return QStringList{}; return QStringList{};
} }
@@ -1183,7 +1213,6 @@ QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType,
return unpacked; return unpacked;
} }
// KN4CRD/XXXX EM73 // KN4CRD/XXXX EM73
// XXXX/KN4CRD EM73 // XXXX/KN4CRD EM73
// KN4CRD/P // KN4CRD/P
@@ -1210,7 +1239,7 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
return frame; return frame;
} }
quint8 type = FrameCompound; quint8 type = Varicode::FrameCompound;
quint16 extra = nmaxgrid; quint16 extra = nmaxgrid;
qDebug() << "try pack cmd" << cmd << directed_cmds.contains(cmd) << Varicode::isCommandAllowed(cmd); qDebug() << "try pack cmd" << cmd << directed_cmds.contains(cmd) << Varicode::isCommandAllowed(cmd);
@@ -1220,7 +1249,7 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
qint8 inum = Varicode::packNum(num, nullptr); qint8 inum = Varicode::packNum(num, nullptr);
extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum, &packedNum); extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum, &packedNum);
type = FrameCompoundDirected; type = Varicode::FrameCompoundDirected;
} else if(!grid.isEmpty()){ } else if(!grid.isEmpty()){
extra = Varicode::packGrid(grid); extra = Varicode::packGrid(grid);
} }
@@ -1232,12 +1261,12 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
} }
QStringList Varicode::unpackCompoundMessage(const QString &text, quint8 *pType, quint8 *pBits3){ QStringList Varicode::unpackCompoundMessage(const QString &text, quint8 *pType, quint8 *pBits3){
quint8 type = FrameCompound; quint8 type = Varicode::FrameCompound;
quint16 extra = nmaxgrid; quint16 extra = nmaxgrid;
quint8 bits3 = 0; quint8 bits3 = 0;
QStringList unpacked = unpackCompoundFrame(text, &type, &extra, &bits3); QStringList unpacked = unpackCompoundFrame(text, &type, &extra, &bits3);
if(unpacked.isEmpty() || (type != FrameCompound && type != FrameCompoundDirected)){ if(unpacked.isEmpty() || (type != Varicode::FrameCompound && type != Varicode::FrameCompoundDirected)){
return QStringList {}; return QStringList {};
} }
@@ -1265,7 +1294,7 @@ QString Varicode::packCompoundFrame(const QString &callsign, quint8 type, quint1
QString frame; QString frame;
// needs to be a compound type... // needs to be a compound type...
if(type == FrameDataCompressed || type == FrameDataUncompressed || type == FrameDirected){ if(type == Varicode::FrameData || type == Varicode::FrameDirected){
return frame; return frame;
} }
@@ -1309,7 +1338,7 @@ 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 ping type... // needs to be a ping type...
if(packed_flag == FrameDataCompressed || packed_flag == FrameDataUncompressed || packed_flag == FrameDirected){ if(packed_flag == Varicode::FrameData || packed_flag == Varicode::FrameDirected){
return unpacked; return unpacked;
} }
@@ -1410,7 +1439,7 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &mycall
cmdOut = cmd.trimmed(); cmdOut = cmd.trimmed();
packed_cmd = directed_cmds[cmdOut]; packed_cmd = directed_cmds[cmdOut];
} }
quint8 packed_flag = FrameDirected; quint8 packed_flag = Varicode::FrameDirected;
quint8 packed_extra = inum; quint8 packed_extra = inum;
// [3][28][28][5],[2][6] = 72 // [3][28][28][5],[2][6] = 72
@@ -1438,7 +1467,7 @@ QStringList Varicode::unpackDirectedMessage(const QString &text, quint8 *pType){
auto bits = Varicode::intToBits(Varicode::unpack72bits(text, &extra), 64); auto bits = Varicode::intToBits(Varicode::unpack72bits(text, &extra), 64);
quint8 packed_flag = Varicode::bitsToInt(bits.mid(0, 3)); quint8 packed_flag = Varicode::bitsToInt(bits.mid(0, 3));
if(packed_flag != FrameDirected){ if(packed_flag != Varicode::FrameDirected){
return unpacked; return unpacked;
} }
@@ -1471,8 +1500,12 @@ QString packHuffMessage(const QString &input, int *n){
QString frame; QString frame;
// [1][71] = 72 // [1][1][70] = 72
QVector<bool> frameBits = {false}; // The first bit is a flag that indicates this is a data frame, technically encoded as [100]
// but, since none of the other frame types start with a 0, we can drop the two zeros and use
// them for encoding the first two bits of the actuall data sent. boom!
// The second bit is a flag that indicates this is not compressed frame (huffman coding)
QVector<bool> frameBits = {true, false};
int i = 0; int i = 0;
@@ -1525,8 +1558,12 @@ QString packCompressedMessage(const QString &input, int *n){
QString frame; QString frame;
// [1][71] = 72 // [1][1][70] = 72
QVector<bool> frameBits = {true}; // The first bit is a flag that indicates this is a data frame, technically encoded as [100]
// but, since none of the other frame types start with a 1, we can drop the two zeros and use
// them for encoding the first two bits of the actuall data sent. boom!
// The second bit is a flag that indicates this is a compressed frame (dense coding)
QVector<bool> frameBits = {true, true};
int i = 0; int i = 0;
foreach(auto pair, JSC::compress(input)){ foreach(auto pair, JSC::compress(input)){
@@ -1564,24 +1601,25 @@ QString packCompressedMessage(const QString &input, int *n){
} }
QString Varicode::packDataMessage(const QString &input, int *n){ QString Varicode::packDataMessage(const QString &input, int *n){
QString huffFrame; QString huffFrame;
int huffChars = 0; int huffChars = 0;
huffFrame = packHuffMessage(input, &huffChars); huffFrame = packHuffMessage(input, &huffChars);
QString compressedFrame; QString compressedFrame;
int compressedChars = 0; int compressedChars = 0;
compressedFrame = packCompressedMessage(input, &compressedChars); compressedFrame = packCompressedMessage(input, &compressedChars);
if(huffChars > compressedChars){ if(huffChars > compressedChars){
if(n) *n = huffChars; if(n) *n = huffChars;
return huffFrame; return huffFrame;
} else { } else {
if(n) *n = compressedChars; if(n) *n = compressedChars;
return compressedFrame; return compressedFrame;
} }
} }
QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
QString Varicode::unpackDataMessage(const QString &text){
QString unpacked; QString unpacked;
if(text.length() < 12 || text.contains(" ")){ if(text.length() < 12 || text.contains(" ")){
@@ -1592,18 +1630,24 @@ 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);
bool isData = bits.at(0);
if(!isData){
return unpacked;
}
bits = bits.mid(1);
bool compressed = bits.at(0); bool compressed = bits.at(0);
int n = bits.lastIndexOf(0); int n = bits.lastIndexOf(0);
bits = bits.mid(1, n-1); bits = bits.mid(1, n-1);
if(compressed){ if(compressed){
// partial word (s,c)-dense coding with code tables
unpacked = JSC::decompress(bits); unpacked = JSC::decompress(bits);
if(pType) *pType = Varicode::FrameDataCompressed;
} else { } 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 = Varicode::FrameDataUncompressed;
} }
return unpacked; return unpacked;
@@ -1654,9 +1698,9 @@ QList<QPair<QString, int>> Varicode::buildMessageFrames(
// 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("`")){
bool lineStartsWithBaseCall = ( bool lineStartsWithBaseCall = (
line.startsWith("@ALLCALL") || line.startsWith("@ALLCALL") ||
line.contains("HEARTBEAT") || Varicode::startsWithCQ(line) ||
Varicode::startsWithCQ(line) Varicode::startsWithHB(line)
); );
#if AUTO_PREPEND_DIRECTED_ALLOW_TEXT_CALLSIGNS #if AUTO_PREPEND_DIRECTED_ALLOW_TEXT_CALLSIGNS
@@ -1823,7 +1867,7 @@ QList<QPair<QString, int>> Varicode::buildMessageFrames(
} }
if(useDat){ if(useDat){
frames.append({ frame, Varicode::JS8CallData }); frames.append({ frame, Varicode::JS8Call });
line = line.mid(m); line = line.mid(m);
} }
} }
@@ -1864,12 +1908,15 @@ void BuildMessageFramesThread::run(){
m_text m_text
); );
QList<QString> frames; // TODO: jsherer - we wouldn't normally use decodedtext.h here... but it's useful for computing the actual frames transmitted.
QList<int> bits; QStringList textList;
foreach(auto pair, results){ qDebug() << "frames:";
frames.append(pair.first); foreach(auto frame, results){
bits.append(pair.second); auto dt = DecodedText(frame.first, frame.second);
qDebug() << "->" << frame << dt.message() << Varicode::frameTypeString(dt.frameType());
textList.append(dt.message());
} }
emit resultReady(frames, bits); auto transmitText = textList.join("");
emit resultReady(transmitText, results.length());
} }
+18 -11
View File
@@ -21,22 +21,28 @@ 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
JS8CallData = 4, // [100] <- raw data frame (no frame type header) JS8CallFlag = 4, // [100] <- flagged frame (no frame type header)
}; };
/*
000 = heartbeat
001 = compound
010 = compound directed
011 = directed
1XX = data, with the X lsb bits dropped
*/
enum FrameType { enum FrameType {
FrameUnknown = 255, // [11111111] <- only used as a sentinel FrameUnknown = 255, // [11111111] <- only used as a sentinel
FrameHeartbeat = 0, // [000] FrameHeartbeat = 0, // [000]
FrameCompound = 1, // [001] FrameCompound = 1, // [001]
FrameCompoundDirected = 2, // [010] FrameCompoundDirected = 2, // [010]
FrameDirected = 3, // [011] FrameDirected = 3, // [011]
FrameReservedA = 4, // [100] <- Reserved for future use, likely an extension of one of these formats. FrameData = 4, // [10X] // but this only encodes the first 2 msb bits and drops the lsb
FrameDataUncompressed = 5, // [101] FrameDataCompressed = 6, // [11X] // but this only encodes the first 2 msb bits and drops the lsb
FrameDataCompressed = 6, // [110]
FrameReservedB = 7, // [111] <- Reserved for future use, likely binary data / other formats.
}; };
static const quint8 FrameTypeMax = 7; static const quint8 FrameTypeMax = 6;
static QString frameTypeString(quint8 type) { static QString frameTypeString(quint8 type) {
const char* FrameTypeStrings[] = { const char* FrameTypeStrings[] = {
@@ -44,10 +50,9 @@ public:
"FrameCompound", "FrameCompound",
"FrameCompoundDirected", "FrameCompoundDirected",
"FrameDirected", "FrameDirected",
"FrameReservedA", "FrameData",
"FrameDataUncompressed", "FrameUnknown", // 5
"FrameDataCompressed", "FrameDataCompressed",
"FrameReservedB"
}; };
if(type > FrameTypeMax){ if(type > FrameTypeMax){
@@ -63,7 +68,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);
@@ -146,7 +153,7 @@ public:
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);
static QList<QPair<QString, int>> buildMessageFrames( static QList<QPair<QString, int>> buildMessageFrames(
QString const& mycall, QString const& mycall,
@@ -172,7 +179,7 @@ public:
QObject *parent=nullptr); QObject *parent=nullptr);
void run() override; void run() override;
signals: signals:
void resultReady(QStringList, QList<int>); void resultReady(QString, int);
private: private:
QString m_mycall; QString m_mycall;
+4
View File
@@ -566,3 +566,7 @@ void WideGraph::setRedFile(QString fRed)
{ {
ui->widePlot->setRedFile(fRed); ui->widePlot->setRedFile(fRed);
} }
void WideGraph::setTurbo(bool turbo){
ui->widePlot->setTurbo(turbo);
}
+1
View File
@@ -50,6 +50,7 @@ public:
void drawRed(int ia, int ib); void drawRed(int ia, int ib);
void setVHF(bool bVHF); void setVHF(bool bVHF);
void setRedFile(QString fRed); void setRedFile(QString fRed);
void setTurbo(bool turbo);
signals: signals:
void freezeDecode2(int n); void freezeDecode2(int n);
+2 -2
View File
@@ -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">