Compare commits

..

70 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
25 changed files with 1432 additions and 710 deletions
+7 -5
View File
@@ -1272,12 +1272,14 @@ if (NOT WIN32 AND NOT APPLE)
#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
${CMAKE_BINARY_DIR}/ljs8call DESTINATION /usr/bin/ RENAME js8call
#COMPONENT runtime
)
install(FILES
${CMAKE_BINARY_DIR}/ljs8call DESTINATION /usr/bin/ RENAME js8call
#COMPONENT runtime
)
endif()
endif (NOT WIN32 AND NOT APPLE)
+46 -32
View File
@@ -642,7 +642,7 @@ private:
bool insert_blank_;
bool DXCC_;
bool ppfx_;
bool clear_DX_;
bool clear_callsign_;
bool miles_;
bool quick_call_;
bool disable_TX_on_73_;
@@ -773,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::DXCC () const {return m_->DXCC_;}
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::quick_call () const {return m_->quick_call_;}
bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;}
@@ -945,6 +945,20 @@ 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
{
return m_->my_qth_.trimmed();
@@ -1014,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,
QSettings * settings, QWidget * parent)
: QDialog {parent}
@@ -1123,6 +1143,16 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
ui_->qth_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_->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->setMaximum (std::numeric_limits<port_type>::max ());
@@ -1353,7 +1383,7 @@ void Configuration::impl::initialize_models ()
ui_->stations_table_view->setEnabled(ui_->auto_switch_bands_check_box->isChecked());
ui_->report_in_comments_check_box->setChecked (report_in_comments_);
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_->quick_call_check_box->setChecked (quick_call_);
ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_);
@@ -1663,7 +1693,7 @@ void Configuration::impl::read_settings ()
insert_blank_ = settings_->value ("InsertBlank", false).toBool ();
DXCC_ = settings_->value ("DXCCEntity", 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 ();
quick_call_ = settings_->value ("QuickCall", false).toBool ();
disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool ();
@@ -1798,7 +1828,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("InsertBlank", insert_blank_);
settings_->setValue ("DXCCEntity", DXCC_);
settings_->setValue ("PrincipalPrefix", ppfx_);
settings_->setValue ("ClearCallGrid", clear_DX_);
settings_->setValue ("ClearCallGrid", clear_callsign_);
settings_->setValue ("Miles", miles_);
settings_->setValue ("QuickCall", quick_call_);
settings_->setValue ("73TxDisable", disable_TX_on_73_);
@@ -1992,7 +2022,7 @@ QStringList splitGroups(QString groupsString, bool filter){
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("@")){
MessageBox::critical_message (this, tr ("The callsign format you provided is not supported"));
return false;
@@ -2005,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
&& !QAudioDeviceInfo::availableDevices (QAudio::AudioInput).empty ())
{
@@ -2253,12 +2289,10 @@ void Configuration::impl::accept ()
Q_ASSERT (audio_output_channel_ <= AudioDevice::Both);
auto_switch_bands_ = ui_->auto_switch_bands_check_box->isChecked();
my_callsign_ = ui_->callsign_line_edit->text ();
my_grid_ = ui_->grid_line_edit->text ();
my_callsign_ = ui_->callsign_line_edit->text ().toUpper();
my_grid_ = ui_->grid_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();
reply_ = ui_->reply_message_line_edit->text().toUpper();
my_qth_ = ui_->qth_message_line_edit->text().toUpper();
@@ -2283,7 +2317,7 @@ void Configuration::impl::accept ()
log_as_DATA_ = ui_->log_as_RTTY_check_box->isChecked ();
report_in_comments_ = ui_->report_in_comments_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 ();
quick_call_ = ui_->quick_call_check_box->isChecked ();
disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked ();
@@ -2684,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)
{
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)
{
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)
{
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)
{
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)
{
QString upper = text.toUpper();
if(text != upper){
ui_->reply_message_line_edit->setText (upper);
}
}
void Configuration::impl::on_add_macro_line_edit_editingFinished ()
@@ -2779,7 +2793,7 @@ void Configuration::impl::on_add_macro_push_button_clicked (bool /* checked */)
{
auto index = next_macros_.index (next_macros_.rowCount () - 1);
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 ();
}
}
+3 -1
View File
@@ -99,6 +99,8 @@ public:
QString my_grid () 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 callsign_aging() const;
QString my_qth () const;
@@ -131,7 +133,7 @@ public:
bool insert_blank () const;
bool DXCC () const;
bool ppfx() const;
bool clear_DX () const;
bool clear_callsign () const;
bool miles () const;
bool quick_call () const;
bool disable_TX_on_73 () const;
+121 -53
View File
@@ -280,7 +280,7 @@
<x>0</x>
<y>0</y>
<width>724</width>
<height>473</height>
<height>489</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_26">
@@ -632,11 +632,65 @@ text message.</string>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_12">
<widget class="QGroupBox" name="groupBox_8">
<property name="title">
<string>Idle Watchdog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_32">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Disable automatic transmissions after:</string>
</property>
<property name="buddy">
<cstring>tx_watchdog_spin_box</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="tx_watchdog_spin_box">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Number of minutes before unattended heartbeat transmissions are aborted.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="specialValueText">
<string>Disabled</string>
</property>
<property name="suffix">
<string> minutes of inactivity</string>
</property>
<property name="prefix">
<string/>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1440</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>60</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="heartbeatGroupBox">
<property name="visible">
<bool>false</bool>
</property>
<property name="title">
<string>Heartbeat (HB)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_21">
<layout class="QVBoxLayout" name="verticalLayout_211">
<item>
<widget class="QCheckBox" name="heartbeat_anywhere_check_box">
<property name="text">
@@ -644,10 +698,38 @@ text message.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="heartbeatGroupBoxOld">
<property name="visible">
<bool>false</bool>
</property>
<property name="title">
<string>Heartbeat (HB)</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_21">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
<widget class="QLabel" name="ping_label_10">
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Heartbeat interval:</string>
</property>
@@ -655,6 +737,9 @@ text message.</string>
</item>
<item>
<widget class="QSpinBox" name="heartbeat_spin_box">
<property name="visible">
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Number of minutes between unattended heartbeat transmissions.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
@@ -684,46 +769,17 @@ text message.</string>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_12">
<item>
<widget class="QLabel" name="label_10">
<property name="text">
<string>Heartbeat idle watchdog timer:</string>
</property>
<property name="buddy">
<cstring>tx_watchdog_spin_box</cstring>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="tx_watchdog_spin_box">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Number of minutes before unattended heartbeat transmissions are aborted.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="specialValueText">
<string>Disabled</string>
</property>
<property name="suffix">
<string> minutes</string>
</property>
<property name="prefix">
<string>after </string>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1440</number>
</property>
<property name="singleStep">
<number>1</number>
</property>
<property name="value">
<number>60</number>
</property>
</widget>
</item>
</layout>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
@@ -1975,7 +2031,7 @@ both here.</string>
<x>0</x>
<y>0</y>
<width>746</width>
<height>519</height>
<height>554</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_30">
@@ -2022,20 +2078,19 @@ both here.</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="clear_DX_check_box">
<item row="1" column="1">
<widget class="QCheckBox" name="clear_callsign_check_box">
<property name="enabled">
<bool>false</bool>
<bool>true</bool>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Check this option to force the clearing of the DX Call
and DX Grid fields when a 73 or free text message is sent.</string>
<string>Check this option to force deselect callsign after logging.</string>
</property>
<property name="text">
<string>Clear &amp;DX call and grid after logging</string>
<string>Deselect callsign after logging</string>
</property>
</widget>
</item>
@@ -2056,7 +2111,7 @@ and DX Grid fields when a 73 or free text message is sent.</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QCheckBox" name="report_in_comments_check_box">
<property name="enabled">
<bool>false</bool>
@@ -2373,6 +2428,19 @@ for assessing propagation and system performance.</string>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
@@ -3999,12 +4067,12 @@ soundcard changes</string>
</connection>
</connections>
<buttongroups>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="PTT_method_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="TX_mode_button_group"/>
</buttongroups>
</ui>
+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
* Documentation is available here: https://docs.google.com/document/d/159S4wqMUVdMA7qBgaSWmU-iDI4C9wd4CuWnetN68O9U/edit?pli=1#heading=h.kfnyge37yfr
# 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
@@ -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
* September 2, 2018 - Version 0.5 released - 3000 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
+1 -1
View File
@@ -1,6 +1,6 @@
# Version number components
set (WSJTX_VERSION_MAJOR 0)
set (WSJTX_VERSION_MINOR 9)
set (WSJTX_VERSION_MINOR 11)
set (WSJTX_VERSION_PATCH 0)
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
+3 -3
View File
@@ -31,7 +31,7 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
"community.<br /><br />"
"JS8Call stands on the shoulder of giants...the takeoff angle "
"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, "
"KI6SSI, "
"K0OG, "
@@ -41,8 +41,8 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
"OH8STN, "
"VA3OSO, "
"VK1MIC, "
"W0FW,</strong><br/><br/>and the many other amateur radio operators who have given "
"JS8Call a chance.");
"W0FW,</strong><br/><br/>and the many other amateur radio operators who have helped<br/>"
"bring JS8Call into the world.");
}
CAboutDlg::~CAboutDlg()
+4 -9
View File
@@ -126,7 +126,7 @@ bool DecodedText::tryUnpackHeartbeat(){
// Heartbeat Alt Type
// ---------------
// 1 0 BCN
// 1 0 HB
// 1 1 CQ
isHeartbeat_ = true;
isAlt_ = isAlt;
@@ -140,7 +140,7 @@ bool DecodedText::tryUnpackHeartbeat(){
cmp.append(parts.at(1));
}
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;
return true;
}
@@ -221,19 +221,14 @@ bool DecodedText::tryUnpackData(){
return false;
}
if((bits_ & Varicode::JS8CallData) != Varicode::JS8CallData){
return false;
}
quint8 type = Varicode::FrameUnknown;
QString data = Varicode::unpackDataMessage(m, &type);
QString data = Varicode::unpackDataMessage(m);
if(data.isEmpty()){
return false;
}
message_ = data;
frameType_ = type;
frameType_ = Varicode::FrameData;
return true;
}
+49 -49
View File
@@ -48,50 +48,50 @@ subroutine foxgen()
do n=1,nslots
i3b=i3bit(n)
if(i3b.eq.0) then
msg=cmsg(n)(1:22) !Standard FT8 message
else
i1=index(cmsg(n),' ') !Special Fox message
i2=index(cmsg(n),';')
i3=index(cmsg(n),'<')
i4=index(cmsg(n),'>')
msg=cmsg(n)(1:i1)//cmsg(n)(i2+1:i3-2)//' '
read(cmsg(n)(i4+2:i4+4),*) irpt
endif
call genft8(msg,mygrid,bcontest,0,msgsent,msgbits,itone)
!if(i3b.eq.0) then
msg=cmsg(n)(1:12) !Standard FT8 message
!else
! i1=index(cmsg(n),' ') !Special Fox message
! i2=index(cmsg(n),';')
! i3=index(cmsg(n),'<')
! i4=index(cmsg(n),'>')
! msg=cmsg(n)(1:i1)//cmsg(n)(i2+1:i3-2)//' '
! read(cmsg(n)(i4+2:i4+4),*) irpt
!endif
call genft8(msg,mygrid,bcontest,i3b,msgsent,msgbits,itone)
! print*,'Foxgen:',n,cmsg(n),msgsent
if(i3b.eq.1) then
icrc10=crc10(c_loc(mycall),12)
nrpt=irpt+30
write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,0
1001 format(56b1.1,b10.10,b6.6,b3.3,b12.12)
read(cbits,1002) msgbits
1002 format(87i1)
cb88=cbits//'0'
read(cb88,1003) i1Msg8BitBytes(1:11)
1003 format(11b8)
icrc12=crc12(c_loc(i1Msg8BitBytes),11)
! icrc12=xor(icrc12, 41) ! TODO: jsherer - could change the crc here
write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,icrc12
read(cbits,1002) msgbits
call encode174(msgbits,codeword) !Encode the test message
! Message structure: S7 D29 S7 D29 S7
itone(1:7)=icos7
itone(36+1:36+7)=icos7
itone(NN-6:NN)=icos7
k=7
do j=1,ND
i=3*j -2
k=k+1
if(j.eq.30) k=k+7
itone(k)=codeword(i)*4 + codeword(i+1)*2 + codeword(i+2)
enddo
endif
!! if(i3b.eq.1) then
!! icrc10=crc10(c_loc(mycall),12)
!! nrpt=irpt+30
!! write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,0
!! 1001 format(56b1.1,b10.10,b6.6,b3.3,b12.12)
!! read(cbits,1002) msgbits
!! 1002 format(87i1)
!!
!! cb88=cbits//'0'
!! read(cb88,1003) i1Msg8BitBytes(1:11)
!! 1003 format(11b8)
!! icrc12=crc12(c_loc(i1Msg8BitBytes),11)
!! ! icrc12=xor(icrc12, 41) ! TODO: jsherer - could change the crc here
!!
!! write(cbits,1001) msgbits(1:56),icrc10,nrpt,i3b,icrc12
!! read(cbits,1002) msgbits
!!
!! call encode174(msgbits,codeword) !Encode the test message
!!
!! ! Message structure: S7 D29 S7 D29 S7
!! itone(1:7)=icos7
!! itone(36+1:36+7)=icos7
!! itone(NN-6:NN)=icos7
!! k=7
!! do j=1,ND
!! i=3*j -2
!! k=k+1
!! if(j.eq.30) k=k+7
!! itone(k)=codeword(i)*4 + codeword(i+1)*2 + codeword(i+2)
!! enddo
!! endif
! Make copies of itone() and msgbits() for ft8sim
itone2=itone
@@ -117,13 +117,13 @@ subroutine foxgen()
! call plotspec(1,wave) !Plot the spectrum
! Apply compression
! rms=sqrt(dot_product(wave,wave)/kz)
! wave=wave/rms
! do i=1,NWAVE
! wave(i)=h1(wave(i))
! enddo
! peak2=maxval(abs(wave))
! wave=wave/peak2
rms=sqrt(dot_product(wave,wave)/kz)
wave=wave/rms
do i=1,NWAVE
wave(i)=h1(wave(i))
enddo
peak2=maxval(abs(wave))
wave=wave/peak2
! call plotspec(2,wave) !Plot the spectrum
+9 -20
View File
@@ -100,6 +100,7 @@ void ADIF::load()
add (extractField (record, "CALL")
, extractField (record, "BAND")
, extractField (record, "MODE")
, extractField (record, "SUBMODE")
, extractField (record, "QSO_DATE"));
}
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;
q.call = call;
q.band = band;
q.mode = mode;
q.submode = submode;
q.date = date;
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)
bool ADIF::match(QString const& call, QString const& band, QString const& mode) const
// return true if in the log same band
bool ADIF::match(QString const& call, QString const& band) const
{
QList<QSO> qsos = _data.values(call);
if (qsos.size()>0)
@@ -134,22 +136,6 @@ bool ADIF::match(QString const& call, QString const& band, QString const& mode)
|| (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;
}
}
@@ -176,7 +162,7 @@ int ADIF::getCount() const
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
, QDateTime const& dateTimeOff, QString const& band, QString const& comments
, 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 += " <gridsquare:" + QString::number(hisGrid.length()) + ">" + hisGrid;
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_rcvd:" + QString::number(rptRcvd.length()) + ">" + rptRcvd;
t += " <qso_date:8>" + dateTimeOn.date().toString("yyyyMMdd");
+4 -4
View File
@@ -23,15 +23,15 @@ class ADIF
public:
void init(QString const& filename);
void load();
void add(QString const& call, QString const& band, QString const& mode, QString const& date);
bool match(QString const& call, QString const& band, QString const& mode) const;
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) const;
QList<QString> getCallList() const;
int getCount() const;
// open ADIF file and append the QSO details. Return true on success
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& band, QString const& comments, QString const& name
, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid
@@ -41,7 +41,7 @@ class ADIF
private:
struct QSO
{
QString call,band,mode,date;
QString call,band,mode,submode,date;
};
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){
return _log.match(call, band, mode);
bool LogBook::hasWorkedBefore(const QString &call, const QString &band){
return _log.match(call, band);
}
void LogBook::match(/*in*/const QString call,
@@ -61,9 +61,8 @@ void LogBook::match(/*in*/const QString call,
{
if (call.length() > 0)
{
QString currentMode = ""; // match any mode
QString currentBand = ""; // match any band
callWorkedBefore = _log.match(call,currentBand,currentMode);
callWorkedBefore = _log.match(call,currentBand);
countryName = _countries.find(call);
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);
if (countryName.length() > 0)
_worked.setAsWorked(countryName);
+2 -2
View File
@@ -20,12 +20,12 @@ class LogBook
{
public:
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,
/*out*/ QString &countryName,
bool &callWorkedBefore,
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:
CountryDat _countries;
+10 -6
View File
@@ -95,12 +95,16 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
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;
hisCall=ui->call->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();
rptRcvd=ui->rcvd->text();
m_dateTimeOn = ui->start_date_time->dateTime ();
@@ -115,10 +119,10 @@ void LogQSO::accept()
//Log this QSO to ADIF file "js8call_log.adi"
QString filename = "js8call_log.adi"; // TODO allow user to set
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);
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)};
if (!adifile.addQSOToFile (ADIF))
{
@@ -148,7 +152,7 @@ void LogQSO::accept()
m_dateTimeOn.time().toString("hh:mm:ss,") +
m_dateTimeOff.date().toString("yyyy-MM-dd,") +
m_dateTimeOff.time().toString("hh:mm:ss,") + hisCall + "," +
hisGrid + "," + strDialFreq + "," + mode +
hisGrid + "," + strDialFreq + "," + (mode == "MFSK" ? "JS8" : mode) +
"," + rptSent + "," + rptRcvd + "," + m_txPower +
"," + comments + "," + name;
QTextStream out(&f);
@@ -157,7 +161,7 @@ void LogQSO::accept()
}
//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();
}
+1 -1
View File
@@ -40,7 +40,7 @@ public slots:
signals:
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& tx_power, QString const& comments
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
+3
View File
@@ -152,6 +152,9 @@
<height>16777215</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
+732 -264
View File
File diff suppressed because it is too large Load Diff
+33 -14
View File
@@ -153,6 +153,7 @@ public slots:
bool ensureCallsignSet(bool alert=true);
bool ensureSelcalCallsignSelected(bool alert=true);
bool ensureKeyNotStuck(QString const& text);
bool ensureNotIdle();
void createMessage(QString const& text);
void createMessageTransmitQueue(QString const& text);
void resetMessageTransmitQueue();
@@ -173,12 +174,14 @@ private slots:
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_Heartbeat_toggled(bool checked);
void on_actionEnable_Selcall_toggled(bool checked);
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_Heartbeats_and_ACKs_triggered(bool checked);
void on_actionShow_Call_Activity_triggered(bool checked);
void on_actionShow_Waterfall_triggered(bool checked);
void on_actionShow_Waterfall_Controls_triggered(bool checked);
@@ -273,6 +276,14 @@ private slots:
void on_rbGenMsg_clicked(bool checked);
void on_rbFreeText_clicked(bool checked);
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_replyMacroButton_clicked();
void on_snrMacroButton_clicked();
@@ -310,11 +321,7 @@ private slots:
bool prepareNextMessageFrame();
bool isFreqOffsetFree(int f, int bw);
int findFreeFreqOffset(int fmin, int fmax, int bw);
void scheduleHeartbeat(bool first=false);
void pauseHeartbeat();
void unpauseHeartbeat();
void checkHeartbeat();
void prepareHeartbeat();
void checkRepeat();
QString calculateDistance(QString const& grid, int *pDistance=nullptr, int *pAzimuth=nullptr);
void on_driftSpinBox_valueChanged(int n);
void on_driftSyncButton_clicked();
@@ -326,10 +333,9 @@ private slots:
void on_tuneButton_clicked (bool);
void on_pbR2T_clicked();
void on_pbT2R_clicked();
void on_heartbeatButton_clicked();
void on_selcalButton_clicked();
void on_turboButton_clicked();
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& tx_power, QString const& comments
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
@@ -356,7 +362,7 @@ private slots:
void on_selcalButton_toggled(bool checked);
void on_tuneButton_toggled(bool checked);
void on_spotButton_toggled(bool checked);
void on_heartbeatButton_toggled(bool checked);
void on_activeButton_toggled(bool checked);
void on_actionMessage_averaging_triggered();
void on_actionFox_Log_triggered();
@@ -664,7 +670,7 @@ private:
QTimer minuteTimer;
QTimer splashTimer;
QTimer p1Timer;
QTimer heartbeatTimer;
QTimer repeatTimer;
QString m_path;
QString m_baseCall;
@@ -723,6 +729,7 @@ private:
QString text;
QString extra;
float tdrift;
QString relayPath;
};
struct ActivityDetail
@@ -747,6 +754,10 @@ private:
QList<ActivityDetail> msgs;
};
int m_bandActivityWidth;
int m_callActivityWidth;
int m_textActivityWidth;
int m_waterfallHeight;
bool m_bandActivityWasVisible;
bool m_rxDirty;
bool m_rxDisplayDirty;
@@ -806,6 +817,8 @@ private:
QQueue<QString> m_txHeartbeatQueue; // ping frames to be sent
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<int, QList<ActivityDetail>>> m_bandActivityCache; // band -> band activity
QMap<QString, QString> m_rxTextCache; // band -> rx text
@@ -834,9 +847,11 @@ private:
QQueue<QString> m_foxQSOinProgress; //QSOs in progress: Fox has sent a report
QQueue<qint64> m_foxRateQueue;
bool m_nextHeartbeatQueued = false;
bool m_nextHeartPaused = false;
bool m_hbHidden;
int m_hbInterval;
int m_cqInterval;
QDateTime m_nextHeartbeat;
QDateTime m_nextCQ;
QDateTime m_dateTimeQSOOn;
QDateTime m_dateTimeLastTX;
@@ -863,7 +878,6 @@ private:
double m_toneSpacing;
int m_firstDecode;
QProgressDialog m_optimizingProgress;
QTimer m_heartbeat;
MessageClient * m_messageClient;
PSK_Reporter *psk_Reporter;
APRSISClient * m_aprsClient;
@@ -902,6 +916,7 @@ private:
void postDecode (bool is_new, QString const& message);
void displayTransmit();
void updateButtonDisplay();
void updateRepeatButtonDisplay();
void updateTextDisplay();
void updateFrameCountEstimate(int count);
void updateTextStatsDisplay(QString text, int count);
@@ -950,6 +965,10 @@ private:
, QString const& his_call
, QString const& his_grid) const;
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 subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus);
void subProcessError (QProcess *, QProcess::ProcessError);
+222 -160
View File
@@ -359,7 +359,7 @@ QPushButton[oob=&quot;true&quot;] {
</string>
</property>
<property name="text">
<string/>
<string>Callsign</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
@@ -411,29 +411,6 @@ color : white;
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="labHeartbeat">
<property name="styleSheet">
<string notr="true">QLabel {
font-family: MS Shell Dlg 2;
font-size: 11pt;
color : white;
}</string>
</property>
<property name="text">
<string>Next Heartbeat: disabled</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="margin">
<number>5</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
@@ -573,43 +550,6 @@ QPushButton:checked {
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="activeButton">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable automatic station replies to directed queries&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>ACTIVE</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="monitorButton">
<property name="enabled">
@@ -776,7 +716,7 @@ QPushButton:checked {
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="heartbeatButton">
<widget class="QPushButton" name="activeButton">
<property name="enabled">
<bool>true</bool>
</property>
@@ -804,7 +744,7 @@ QPushButton:checked {
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable the automatic heartbeat transmission&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Register your station as active or idle&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
@@ -820,7 +760,7 @@ QPushButton:checked {
}</string>
</property>
<property name="text">
<string>HB</string>
<string>ACTIVE</string>
</property>
<property name="checkable">
<bool>true</bool>
@@ -1030,6 +970,52 @@ QPushButton:checked {
</property>
</spacer>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="turboButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="visible">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
background-color:lightgray;
padding:0.25em 0.25em; font-weight:normal;
border-style:solid;
border-width:0px;
border-radius:2px;
}
QPushButton:checked {
background-color:#6699ff;
}</string>
</property>
<property name="text">
<string>TURBO</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@@ -1284,6 +1270,14 @@ QTextEdit[transmitting=&quot;true&quot;] {
<attribute name="verticalHeaderVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string>★</string>
</property>
<property name="textAlignment">
<set>AlignCenter</set>
</property>
</column>
<column>
<property name="text">
<string>Callsign</string>
@@ -1361,8 +1355,11 @@ QTextEdit[transmitting=&quot;true&quot;] {
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="11">
<widget class="QPushButton" name="queryButton">
<item row="1" column="16">
<widget class="QPushButton" name="startTxButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>0</width>
@@ -1370,14 +1367,27 @@ QTextEdit[transmitting=&quot;true&quot;] {
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send a directed message to another station&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Start transmitting&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton:checked {
background-color: #00ff00;
color:#555;
}
QPushButton[transmitting=&quot;true&quot;]{
background:#ff0000;
color:#555;
}</string>
</property>
<property name="text">
<string>Directed</string>
<string>Send</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="16">
<item row="1" column="17">
<widget class="QPushButton" name="stopTxButton">
<property name="minimumSize">
<size>
@@ -1393,7 +1403,7 @@ QTextEdit[transmitting=&quot;true&quot;] {
</property>
</widget>
</item>
<item row="1" column="14">
<item row="1" column="15">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@@ -1410,7 +1420,7 @@ QTextEdit[transmitting=&quot;true&quot;] {
</spacer>
</item>
<item row="1" column="5">
<widget class="QPushButton" name="qtcMacroButton">
<widget class="QPushButton" name="qthMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
@@ -1418,78 +1428,14 @@ QTextEdit[transmitting=&quot;true&quot;] {
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send your station message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send your station location message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>QTC</string>
<string>QTH</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="snrMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send an SNR message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>SNR</string>
</property>
</widget>
</item>
<item row="1" column="7">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="replyMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reply to a CQ&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Reply</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QPushButton" name="macrosMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send a saved message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Saved</string>
</property>
</widget>
</item>
<item row="1" column="12">
<item row="1" column="13">
<widget class="QPushButton" name="deselectButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@@ -1512,7 +1458,7 @@ QTextEdit[transmitting=&quot;true&quot;] {
</widget>
</item>
<item row="1" column="4">
<widget class="QPushButton" name="qthMacroButton">
<widget class="QPushButton" name="snrMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
@@ -1520,14 +1466,46 @@ QTextEdit[transmitting=&quot;true&quot;] {
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send your station location message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send an SNR message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>QTH</string>
<string>SNR</string>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="1" column="8">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="replyMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reply to a CQ&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Reply</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="cqMacroButton">
<property name="minimumSize">
<size>
@@ -1538,19 +1516,25 @@ QTextEdit[transmitting=&quot;true&quot;] {
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send a CQ message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton:checked {
font-weight:bold;
color:black;
}</string>
</property>
<property name="text">
<string>CQ</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="flat">
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="15">
<widget class="QPushButton" name="startTxButton">
<property name="enabled">
<bool>false</bool>
</property>
<item row="1" column="6">
<widget class="QPushButton" name="qtcMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
@@ -1558,20 +1542,64 @@ QTextEdit[transmitting=&quot;true&quot;] {
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Start transmitting&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send your station message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>QTC</string>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QPushButton" name="macrosMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send a saved message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Saved</string>
</property>
</widget>
</item>
<item row="1" column="12">
<widget class="QPushButton" name="queryButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send a directed message to another station&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Directed</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="hbMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p align=&quot;justify&quot;&gt;Send a Heartbeat message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton:checked {
background-color: #00ff00;
color:#555;
}
QPushButton[transmitting=&quot;true&quot;]{
background:yellow;
color:#555;
<string notr="true">QPushButton:checked {
font-weight:bold;
color:black;
}</string>
</property>
<property name="text">
<string>Send</string>
<string>HB</string>
</property>
<property name="checkable">
<bool>true</bool>
@@ -4723,10 +4751,10 @@ list. The list can be maintained in Settings (F2).</string>
<property name="title">
<string>&amp;View</string>
</property>
<addaction name="actionShow_Tooltips"/>
<addaction name="actionShow_Frequency_Clock"/>
<addaction name="separator"/>
<addaction name="actionShow_Band_Activity"/>
<addaction name="actionShow_Band_Heartbeats_and_ACKs"/>
<addaction name="actionShow_Band_Activity_Columns"/>
<addaction name="actionSort_Band_Activity"/>
<addaction name="separator"/>
@@ -4738,6 +4766,8 @@ list. The list can be maintained in Settings (F2).</string>
<addaction name="actionShow_Waterfall_Controls"/>
<addaction name="actionShow_Time_Drift_Controls"/>
<addaction name="separator"/>
<addaction name="actionShow_Fullscreen"/>
<addaction name="actionShow_Tooltips"/>
<addaction name="actionReset_Window_Sizes"/>
</widget>
<widget class="QMenu" name="menu_Log">
@@ -4756,9 +4786,12 @@ list. The list can be maintained in Settings (F2).</string>
<string>C&amp;ontrol</string>
</property>
<addaction name="actionEnable_Spotting"/>
<addaction name="actionEnable_Heartbeat"/>
<addaction name="actionEnable_Active"/>
<addaction name="actionEnable_Auto_Reply"/>
<addaction name="actionEnable_Selcall"/>
<addaction name="separator"/>
<addaction name="actionHeartbeat"/>
<addaction name="actionCQ"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuConfig"/>
@@ -5577,12 +5610,12 @@ list. The list can be maintained in Settings (F2).</string>
<string>Enable Spotting</string>
</property>
</action>
<action name="actionEnable_Heartbeat">
<action name="actionEnable_Active">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Enable Heartbeat</string>
<string>Enable Active</string>
</property>
</action>
<action name="actionEnable_Auto_Reply">
@@ -5601,6 +5634,35 @@ list. The list can be maintained in Settings (F2).</string>
<string>Enable Selective Calling</string>
</property>
</action>
<action name="actionShow_Fullscreen">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show Fullscreen</string>
</property>
<property name="shortcut">
<string>F11</string>
</property>
</action>
<action name="actionHeartbeat">
<property name="text">
<string>Heartbeat...</string>
</property>
</action>
<action name="actionCQ">
<property name="text">
<string>CQ...</string>
</property>
</action>
<action name="actionShow_Band_Heartbeats_and_ACKs">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show Band Heartbeats and ACKs</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
+31
View File
@@ -27,6 +27,7 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
m_plot2dGain {0},
m_plot2dZero {0},
m_nSubMode {0},
m_turbo {false},
m_Running {false},
m_paintEventBusy {false},
m_fftBinWidth {1500.0/2048.0},
@@ -587,6 +588,9 @@ void CPlotter::DrawOverlay() //DrawOverlay()
if(m_mode=="FT8"){
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);
overPainter.initFrom(this);
overPainter.setCompositionMode(QPainter::CompositionMode_Source);
@@ -595,10 +599,22 @@ void CPlotter::DrawOverlay() //DrawOverlay()
overPainter.setPen(thinRed);
overPainter.drawLine(0, 30, 0, 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.drawLine(0, 26, fwidth, 26);
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);
hoverPainter.initFrom(this);
@@ -607,6 +623,12 @@ void CPlotter::DrawOverlay() //DrawOverlay()
hoverPainter.setPen(QPen(Qt::white));
hoverPainter.drawLine(0, 30, 0, 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
int f = FreqfromX(m_lastMouseX);
@@ -865,6 +887,15 @@ void CPlotter::setDialFreq(double d)
void CPlotter::setRxBand(QString band)
{
m_rxBand=band;
DrawOverlay();
update();
}
void CPlotter::setTurbo(bool turbo)
{
m_turbo=turbo;
DrawOverlay();
update();
}
void CPlotter::setFlatten(bool b1, bool b2)
+2
View File
@@ -81,6 +81,7 @@ public:
void setFlatten(bool b1, bool b2);
void setTol(int n);
void setRxBand(QString band);
void setTurbo(bool turbo);
void setReference(bool b) {m_bReference = b;}
bool Reference() const {return m_bReference;}
void drawRed(int ia, int ib, float swide[]);
@@ -147,6 +148,7 @@ private:
QString m_rxBand;
QString m_redFile;
bool m_turbo;
bool m_Running;
bool m_paintEventBusy;
bool m_dataFromDisk;
+114 -68
View File
@@ -27,6 +27,7 @@
#include "varicode.h"
#include "jsc.h"
#include "decodedtext.h"
#include <cmath>
@@ -54,26 +55,30 @@ QMap<QString, int> directed_cmds = {
{" QTC?", 2 }, // query station message
{"&", 2 }, // compat
{" HEARING?", 3 }, // query station calls heard
{"$", 3 }, // compat
{" GRID?", 4 }, // query grid
{"^", 4 }, // compat
{">", 5 }, // relay message
{" STATUS?", 6 }, // query idle message
{"*", 6 }, // compat
{">", 5 }, // relay message
{"#", 8 }, // all or nothing message
//{"!", 7 }, // unused
//{"#", 8 }, // unused
//{"!", 7 }, // alert message
//{"$", 3 }, // query station(s) heard
{" TU", 9 }, // thank you
{" TU", 9 }, // thank you
{" ACTIVE", 10 }, // i am active
{" IDLE", 11 }, // i am idle
{" ACTIVE", 10 }, // i have been active in the past 10 minutes
{" IDLE", 11 }, // i have not been active in the past 10 minutes
{" HB", -1 }, // this is my heartbeat (unused except for faux processing of HBs as directed commands)
{" HEARTBEAT", -1 }, // this is my ping (unused except for faux processing of pings 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
@@ -87,42 +92,42 @@ QMap<QString, int> directed_cmds = {
{" RR", 21 }, // roger roger
{" QSL?", 22 }, // do you copy?
{" QSL", 23 }, // i copy
{" QRZ?", 24 }, // who is calling me
// {" ", 24 }, // unused
{" SNR", 25 }, // seen a station at the provided snr
{" NO", 26 }, // negative confirm
{" YES", 27 }, // confirm
{" 73", 28 }, // best regards, end of contact
{" ACK", 29 }, // acknowledge
{" 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 = {
{ 5, 16 },
{ 8, 16 },
{ 13, 16 },
{ 14, 16 },
{ 15, 0 }
};
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|TU)(?=[ ]|$))|[?*^&@#> ]))?");
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_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("^" +
callsign_pattern +
optional_cmd_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*[`]" +
callsign_pattern +
@@ -204,6 +209,12 @@ QMap<quint32, QString> cqs = {
{ 7, "CQ CQ CQ"},
};
QMap<quint32, QString> hbs = {
{ 0, "HB ACTIVE" },
{ 1, "HB IDLE" },
};
QMap<int, int> dbm2mw = {
{0 , 1}, // 1mW
{3 , 2}, // 2mW
@@ -290,6 +301,13 @@ QString Varicode::cqString(int number){
return cqs[number];
}
QString Varicode::hbString(int number){
if(!hbs.contains(number)){
return QString{};
}
return hbs[number];
}
bool Varicode::startsWithCQ(QString text){
foreach(auto cq, cqs.values()){
if(text.startsWith(cq)){
@@ -299,6 +317,15 @@ bool Varicode::startsWithCQ(QString text){
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){
if(snr < -60 || snr > 60){
return QString();
@@ -992,7 +1019,7 @@ quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
// [1][X][6]
// X = 0 == SNR
// X = 1 == ACK
value = ((1 << 1) | (int)(cmdStr == " HEARTBEAT ACK")) << 6;
value = ((1 << 1) | (int)(cmdStr == " ACK")) << 6;
value = value + (num & ((1<<6)-1));
if(pPackedNum) *pPackedNum = true;
} else {
@@ -1010,7 +1037,7 @@ quint8 Varicode::unpackCmd(quint8 value, quint8 *pNum){
auto cmd = directed_cmds[" SNR"];
if(value & (1<<6)){
cmd = directed_cmds[" HEARTBEAT ACK"];
cmd = directed_cmds[" ACK"];
}
return cmd;
} else {
@@ -1119,7 +1146,8 @@ bool Varicode::isCompoundCallsign(const QString &callsign){
// CQCQCQ EM73
// CQ DX EM73
// CQ QRP EM73
// HEARTBEAT EM73
// HB ACTIVE EM73
// HB IDLE EM73
QString Varicode::packHeartbeatMessage(QString const &text, const QString &callsign, int *n){
QString frame;
@@ -1133,8 +1161,8 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
// Heartbeat Alt Type
// ---------------
// 1 0 HEARTBEAT
// 1 1 CQCQCQ
// 1 0 HB
// 1 1 CQ
auto type = parsedText.captured("type");
auto isAlt = type.startsWith("CQ");
@@ -1149,13 +1177,14 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
packed_extra = Varicode::packGrid(extra);
}
quint8 cqNumber = hbs.key(type, 0);
if(isAlt){
packed_extra |= (1<<15);
cqNumber = cqs.key(type, 0);
}
quint8 cqNumber = cqs.key(type, 0);
frame = packCompoundFrame(callsign, FrameHeartbeat, packed_extra, cqNumber);
frame = packCompoundFrame(callsign, Varicode::FrameHeartbeat, packed_extra, cqNumber);
if(frame.isEmpty()){
if(n) *n = 0;
return frame;
@@ -1166,12 +1195,12 @@ QString Varicode::packHeartbeatMessage(QString const &text, const QString &calls
}
QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType, bool * isAlt, quint8 * pBits3){
quint8 type = FrameHeartbeat;
quint8 type = Varicode::FrameHeartbeat;
quint16 num = nmaxgrid;
quint8 bits3 = 0;
QStringList unpacked = unpackCompoundFrame(text, &type, &num, &bits3);
if(unpacked.isEmpty() || type != FrameHeartbeat){
if(unpacked.isEmpty() || type != Varicode::FrameHeartbeat){
return QStringList{};
}
@@ -1184,7 +1213,6 @@ QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType,
return unpacked;
}
// KN4CRD/XXXX EM73
// XXXX/KN4CRD EM73
// KN4CRD/P
@@ -1211,7 +1239,7 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
return frame;
}
quint8 type = FrameCompound;
quint8 type = Varicode::FrameCompound;
quint16 extra = nmaxgrid;
qDebug() << "try pack cmd" << cmd << directed_cmds.contains(cmd) << Varicode::isCommandAllowed(cmd);
@@ -1221,7 +1249,7 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
qint8 inum = Varicode::packNum(num, nullptr);
extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum, &packedNum);
type = FrameCompoundDirected;
type = Varicode::FrameCompoundDirected;
} else if(!grid.isEmpty()){
extra = Varicode::packGrid(grid);
}
@@ -1233,12 +1261,12 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
}
QStringList Varicode::unpackCompoundMessage(const QString &text, quint8 *pType, quint8 *pBits3){
quint8 type = FrameCompound;
quint8 type = Varicode::FrameCompound;
quint16 extra = nmaxgrid;
quint8 bits3 = 0;
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 {};
}
@@ -1266,7 +1294,7 @@ QString Varicode::packCompoundFrame(const QString &callsign, quint8 type, quint1
QString frame;
// needs to be a compound type...
if(type == FrameDataCompressed || type == FrameDataUncompressed || type == FrameDirected){
if(type == Varicode::FrameData || type == Varicode::FrameDirected){
return frame;
}
@@ -1310,7 +1338,7 @@ QStringList Varicode::unpackCompoundFrame(const QString &text, quint8 *pType, qu
quint8 packed_flag = Varicode::bitsToInt(bits.mid(0, 3));
// 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;
}
@@ -1411,7 +1439,7 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &mycall
cmdOut = cmd.trimmed();
packed_cmd = directed_cmds[cmdOut];
}
quint8 packed_flag = FrameDirected;
quint8 packed_flag = Varicode::FrameDirected;
quint8 packed_extra = inum;
// [3][28][28][5],[2][6] = 72
@@ -1439,7 +1467,7 @@ QStringList Varicode::unpackDirectedMessage(const QString &text, quint8 *pType){
auto bits = Varicode::intToBits(Varicode::unpack72bits(text, &extra), 64);
quint8 packed_flag = Varicode::bitsToInt(bits.mid(0, 3));
if(packed_flag != FrameDirected){
if(packed_flag != Varicode::FrameDirected){
return unpacked;
}
@@ -1472,8 +1500,12 @@ QString packHuffMessage(const QString &input, int *n){
QString frame;
// [1][71] = 72
QVector<bool> frameBits = {false};
// [1][1][70] = 72
// 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;
@@ -1526,8 +1558,12 @@ QString packCompressedMessage(const QString &input, int *n){
QString frame;
// [1][71] = 72
QVector<bool> frameBits = {true};
// [1][1][70] = 72
// 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;
foreach(auto pair, JSC::compress(input)){
@@ -1565,24 +1601,25 @@ QString packCompressedMessage(const QString &input, int *n){
}
QString Varicode::packDataMessage(const QString &input, int *n){
QString huffFrame;
int huffChars = 0;
huffFrame = packHuffMessage(input, &huffChars);
QString huffFrame;
int huffChars = 0;
huffFrame = packHuffMessage(input, &huffChars);
QString compressedFrame;
int compressedChars = 0;
compressedFrame = packCompressedMessage(input, &compressedChars);
QString compressedFrame;
int compressedChars = 0;
compressedFrame = packCompressedMessage(input, &compressedChars);
if(huffChars > compressedChars){
if(n) *n = huffChars;
return huffFrame;
} else {
if(n) *n = compressedChars;
return compressedFrame;
}
if(huffChars > compressedChars){
if(n) *n = huffChars;
return huffFrame;
} else {
if(n) *n = compressedChars;
return compressedFrame;
}
}
QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
QString Varicode::unpackDataMessage(const QString &text){
QString unpacked;
if(text.length() < 12 || text.contains(" ")){
@@ -1593,18 +1630,24 @@ QString Varicode::unpackDataMessage(const QString &text, quint8 *pType){
quint64 value = Varicode::unpack72bits(text, &rem);
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);
int n = bits.lastIndexOf(0);
bits = bits.mid(1, n-1);
if(compressed){
// partial word (s,c)-dense coding with code tables
unpacked = JSC::decompress(bits);
if(pType) *pType = Varicode::FrameDataCompressed;
} else {
// huff decode the bits (without escapes)
unpacked = Varicode::huffDecode(Varicode::defaultHuffTable(), bits);
if(pType) *pType = Varicode::FrameDataUncompressed;
}
return unpacked;
@@ -1655,9 +1698,9 @@ QList<QPair<QString, int>> Varicode::buildMessageFrames(
// and if this isn't a raw message (starting with "`")... then...
if(!selectedCall.isEmpty() && !line.startsWith(selectedCall) && !line.startsWith("`")){
bool lineStartsWithBaseCall = (
line.startsWith("@ALLCALL") ||
line.contains("HEARTBEAT") ||
Varicode::startsWithCQ(line)
line.startsWith("@ALLCALL") ||
Varicode::startsWithCQ(line) ||
Varicode::startsWithHB(line)
);
#if AUTO_PREPEND_DIRECTED_ALLOW_TEXT_CALLSIGNS
@@ -1824,7 +1867,7 @@ QList<QPair<QString, int>> Varicode::buildMessageFrames(
}
if(useDat){
frames.append({ frame, Varicode::JS8CallData });
frames.append({ frame, Varicode::JS8Call });
line = line.mid(m);
}
}
@@ -1865,12 +1908,15 @@ void BuildMessageFramesThread::run(){
m_text
);
QList<QString> frames;
QList<int> bits;
foreach(auto pair, results){
frames.append(pair.first);
bits.append(pair.second);
// 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());
}
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
JS8CallFirst = 1, // [001] <- the first 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 {
FrameUnknown = 255, // [11111111] <- only used as a sentinel
FrameHeartbeat = 0, // [000]
FrameCompound = 1, // [001]
FrameCompoundDirected = 2, // [010]
FrameDirected = 3, // [011]
FrameReservedA = 4, // [100] <- Reserved for future use, likely an extension of one of these formats.
FrameDataUncompressed = 5, // [101]
FrameDataCompressed = 6, // [110]
FrameReservedB = 7, // [111] <- Reserved for future use, likely binary data / other formats.
FrameData = 4, // [10X] // but this only encodes the first 2 msb bits and drops the lsb
FrameDataCompressed = 6, // [11X] // but this only encodes the first 2 msb bits and drops the lsb
};
static const quint8 FrameTypeMax = 7;
static const quint8 FrameTypeMax = 6;
static QString frameTypeString(quint8 type) {
const char* FrameTypeStrings[] = {
@@ -44,10 +50,9 @@ public:
"FrameCompound",
"FrameCompoundDirected",
"FrameDirected",
"FrameReservedA",
"FrameDataUncompressed",
"FrameData",
"FrameUnknown", // 5
"FrameDataCompressed",
"FrameReservedB"
};
if(type > FrameTypeMax){
@@ -63,7 +68,9 @@ public:
static QMap<QString, QString> defaultHuffTable();
static QString cqString(int number);
static QString hbString(int number);
static bool startsWithCQ(QString text);
static bool startsWithHB(QString text);
static QString formatSNR(int snr);
static QString formatPWR(int dbm);
@@ -146,7 +153,7 @@ public:
static QStringList unpackDirectedMessage(QString const& text, quint8 *pType);
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(
QString const& mycall,
@@ -172,7 +179,7 @@ public:
QObject *parent=nullptr);
void run() override;
signals:
void resultReady(QStringList, QList<int>);
void resultReady(QString, int);
private:
QString m_mycall;
+4
View File
@@ -566,3 +566,7 @@ void WideGraph::setRedFile(QString 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 setVHF(bool bVHF);
void setRedFile(QString fRed);
void setTurbo(bool turbo);
signals:
void freezeDecode2(int n);