Compare commits

...

69 Commits

Author SHA1 Message Date
Jordan Sherer 536f017fd4 Bump to v0.5.1 2018-09-01 13:43:16 -04:00
Jordan Sherer 5c313af3ab Removed PWR. Added APRS SSID 2018-09-01 10:34:12 -04:00
Jordan Sherer 046fe83193 Fixed compound buffered commands double printing in the rx window 2018-08-31 22:29:13 -04:00
Jordan Sherer e861308d70 Added auto-prefix messages with directed callsigns 2018-08-31 21:30:34 -04:00
Jordan Sherer 6dcf4b96d2 Fixed bug in waterfall displaying mouse hover without mouse over 2018-08-31 19:04:57 -04:00
Jordan Sherer f00f5e23c1 Updated message textbox placeholder default 2018-08-31 19:03:31 -04:00
Jordan Sherer 2e8cde4193 Added deselect to the activity menus 2018-08-31 09:59:43 -04:00
Jordan Sherer 7caa7c83b8 Updated GRID command to no longer ACK a reply. It was giving off the wrong impression 2018-08-30 20:45:51 -04:00
Jordan Sherer 08d8beed64 Fixed issue with double printing of directed and undirected activity. Fixed enter key press with no message 2018-08-30 17:19:58 -04:00
Jordan Sherer e5347eb4b6 Fixed scrolling bug for band activity and call activity lists 2018-08-30 16:13:43 -04:00
Jordan Sherer 64022c18b6 Added compound callsigns to APRS position comment 2018-08-30 15:01:43 -04:00
Jordan Sherer 42c8d1c0bb Updated APRS client to be more resilient to server failure 2018-08-30 14:31:31 -04:00
Jordan Sherer 6ab3d32e3b Updated APRS spotting connections for better reliability 2018-08-30 12:18:20 -04:00
Jordan Sherer 2b62734437 Fixed bug with SNR report menu item 2018-08-29 22:17:14 -04:00
Jordan Sherer 95a91fb526 Updated listCopyReverse to support older versions of Qt 2018-08-29 16:00:25 -04:00
Jordan Sherer 081bc0380b Added reply message to configuration 2018-08-29 12:32:09 -04:00
Jordan Sherer 77715347c7 Reordered the query menu 2018-08-29 12:11:32 -04:00
Jordan Sherer 712580d08c Added QSO query for finding a remote station 2018-08-29 12:08:22 -04:00
Jordan Sherer 084765f271 Updated beacon default to 30 minutes 2018-08-29 11:28:26 -04:00
Jordan Sherer d2b7229815 Remove QSY checkbox from settings 2018-08-29 11:17:10 -04:00
Jordan Sherer 63739b9d31 Added scroll wheel support for waterfall. Added hover indicator to make selection of signal easier 2018-08-29 11:06:46 -04:00
Jordan Sherer d1b239201c Removed from callsign from message save log...redundant 2018-08-28 21:06:49 -04:00
Jordan Sherer f06df77db2 Added writing hashed messages to a file on disk 2018-08-28 20:58:39 -04:00
Jordan Sherer 2250589f83 Bump EOL 2018-08-28 16:49:44 -04:00
Jordan Sherer 65a19e4707 Added API entry for logging QSOs 2018-08-28 16:44:21 -04:00
Jordan Sherer c8c4f98610 Added offset to call activity display and sort menu 2018-08-28 16:35:14 -04:00
Jordan Sherer 0ecbbd0da1 Added reply button back into the main window 2018-08-28 16:04:49 -04:00
Jordan Sherer b5cebe41e8 Added caching and restoring band/call/rx activity on band change 2018-08-28 15:45:23 -04:00
Jordan Sherer 83b05df312 Added APRS payload sends to APRS-IS 2018-08-28 15:13:38 -04:00
Jordan Sherer 541bd8bca3 Example email over APRS 2018-08-28 09:45:22 -04:00
Jordan Sherer 565bdb5690 Added function to determine the checksum size needed for a buffered command 2018-08-27 22:04:17 -04:00
Jordan Sherer 7868c3fe70 Added double spacing between message lines 2018-08-27 21:41:22 -04:00
Jordan Sherer adcc728492 Added spotting to APRS-IS for grids larger than 4 characters. Added supporting commands for QTH QTC and GRID 2018-08-27 21:19:38 -04:00
Jordan Sherer 2fa1fcd4f8 Generic label for spotting 2018-08-24 09:39:33 -04:00
Jordan Sherer 8eb0fc327d Added option to enable/disable immediate transmission of directed items 2018-08-24 09:38:00 -04:00
Jordan Sherer e6f83e999b Added a few additional directed message short commands 2018-08-24 09:21:17 -04:00
Jordan Sherer b10ccc370f Added a few additional optional directeds 2018-08-24 00:20:10 -04:00
Jordan Sherer 121ffb48f6 Renamed labeling for sort 2018-08-24 00:11:21 -04:00
Jordan Sherer 4698db27f6 Bump EOL. Ensure grid is also configured before transmit. Optionally show warning message. Display configuration when not configured on application load 2018-08-23 23:59:15 -04:00
Jordan Sherer fe1463b730 Fixed overlay bounds 2018-08-23 17:25:48 -04:00
Jordan Sherer ad154cb2e6 Adjusted 160m frequency 2018-08-23 13:13:28 -04:00
Jordan Sherer 5166b1e0dd Block lower 500Hz from being used to allow frequency separation 2018-08-23 13:10:20 -04:00
Jordan Sherer 5d0e91a5ed Added menu items for band and call activity sorting in the main menu 2018-08-23 12:24:47 -04:00
Jordan Sherer c01238f5e0 Added sorting of band activity and call activity window 2018-08-23 11:59:20 -04:00
Jordan Sherer 726484a05a Remove restriction of grid locator to 4 or 6 chars. Upped to 16 chars 2018-08-22 15:15:30 -04:00
Jordan Sherer b7d2a370f8 Default to spotting 2018-08-17 17:37:43 -04:00
Jordan Sherer 6c8902d802 Tweaks to the directed menu 2018-08-17 11:13:49 -04:00
Jordan Sherer 1002dcbc1b Added enable/disable for UDP API. Added DATA for logging instead of RTTY 2018-08-17 10:07:17 -04:00
Jordan Sherer f2ca9caec7 Added right click menu to the band activity window 2018-08-17 09:35:45 -04:00
Jordan Sherer 96ca7786e5 Fixed issue with background colors 2018-08-17 09:27:31 -04:00
Jordan Sherer eecde27cd8 Open settings if no call has been set 2018-08-17 09:18:49 -04:00
Jordan Sherer d4bb4cf49a Bump to 0.5.0 2018-08-16 17:47:02 -04:00
Jordan Sherer db74c22890 Make sure to initialize the structs 2018-08-16 17:46:53 -04:00
Jordan Sherer 69b90b243a Fixed issue with allcall buffering responses while autoreply is disabled 2018-08-16 16:41:01 -04:00
Jordan Sherer 9bac05c86c Bump version of frequencies settings key to intialize new frequencies 2018-08-16 16:02:44 -04:00
Jordan Sherer fde19eebd8 Updated frequencies to be closer aligned with existing allocations 2018-08-16 15:53:46 -04:00
Jordan Sherer 6b4390fe5c Added warning message with a timeout for automatic band switching 2018-08-16 15:19:43 -04:00
Jordan Sherer ad4e567392 Fixed display of allcalls. No longer red 2018-08-16 11:31:10 -04:00
Jordan Sherer 612df625ed Added ability to change directed message window background color 2018-08-16 11:02:23 -04:00
Jordan Sherer 9475ea7461 Added a couple more frequency options. Decisions. Decisions. 2018-08-16 10:01:25 -04:00
Jordan Sherer 5fad5497d2 Fixed jumping of band activity and call activity tables on update 2018-08-15 23:24:16 -04:00
Jordan Sherer 9815c4dde9 API: Added RX.GET_CALL_SELECTED 2018-08-15 22:31:01 -04:00
Jordan Sherer 60c0f24ef8 Fixed restricted characterset for configuration messages and macros 2018-08-15 22:29:23 -04:00
Jordan Sherer e74e20680a Added alternate frequencies we can switch to for the next build 2018-08-15 21:54:35 -04:00
Jordan Sherer ee44e2e5d7 Fixed issue with QSY during message sending 2018-08-15 20:57:30 -04:00
Jordan Sherer 43574b10b1 Slight modified frequencies for 80m and 12m to avoid PSK 2018-08-15 16:46:19 -04:00
Jordan Sherer 08f046c289 Fixed incorrect labels for frame type enum 2018-08-14 22:26:49 -04:00
Jordan Sherer 5f4a66e916 Added warning message about empty callsign before transmitting 2018-08-14 12:09:14 -04:00
Jordan Sherer bc97c96a5b Added tooltips and better labels 2018-08-14 10:53:30 -04:00
26 changed files with 2469 additions and 1013 deletions
+297
View File
@@ -0,0 +1,297 @@
#include "APRSISClient.h"
#include <cmath>
#include "Radio.hpp"
#include "varicode.h"
APRSISClient::APRSISClient(QString host, quint16 port, QObject *parent):
QTcpSocket(parent),
m_host(host),
m_port(port)
{
connect(&m_timer, &QTimer::timeout, this, &APRSISClient::sendReports);
m_timer.setInterval(30*1000); // every 30 seconds
m_timer.start();
}
quint32 APRSISClient::hashCallsign(QString callsign){
// based on: https://github.com/hessu/aprsc/blob/master/src/passcode.c
QByteArray rootCall = QString(callsign.split("-").first().toUpper()).toLocal8Bit() + '\0';
quint32 hash = 0x73E2;
int i = 0;
int len = rootCall.length();
while(i+1 < len){
hash ^= rootCall.at(i) << 8;
hash ^= rootCall.at(i+1);
i += 2;
}
return hash & 0x7FFF;
}
QString APRSISClient::loginFrame(QString callsign){
auto loginFrame = QString("user %1 pass %2 ver %3\n");
loginFrame = loginFrame.arg(callsign);
loginFrame = loginFrame.arg(hashCallsign(callsign));
loginFrame = loginFrame.arg("FT8Call");
return loginFrame;
}
QList<QStringList> findall(QRegularExpression re, QString content){
int pos = 0;
QList<QStringList> all;
while(pos < content.length()){
auto match = re.match(content, pos);
if(!match.hasMatch()){
break;
}
all.append(match.capturedTexts());
pos = match.capturedEnd();
}
return all;
}
inline long
floordiv (long num, long den)
{
if (0 < (num^den))
return num/den;
else
{
ldiv_t res = ldiv(num,den);
return (res.rem)? res.quot-1
: res.quot;
}
}
// convert an arbitrary length grid locator to a high precision lat/lon
QPair<float, float> APRSISClient::grid2deg(QString locator){
QString grid = locator.toUpper();
float lat = -90;
float lon = -90;
auto lats = findall(QRegularExpression("([A-X])([A-X])"), grid);
auto lons = findall(QRegularExpression("(\\d)(\\d)"), grid);
int valx[22];
int valy[22];
int i = 0;
int tot = 0;
char A = 'A';
foreach(QStringList matched, lats){
char x = matched.at(1).at(0).toLatin1();
char y = matched.at(2).at(0).toLatin1();
valx[i*2] = x-A;
valy[i*2] = y-A;
i++;
tot++;
}
i = 0;
foreach(QStringList matched, lons){
int x = matched.at(1).toInt();
int y = matched.at(2).toInt();
valx[i*2+1]=x;
valy[i*2+1]=y;
i++;
tot++;
}
for(int i = 0; i < tot; i++){
int x = valx[i];
int y = valy[i];
int z = i - 1;
float scale = pow(10, floordiv(-(z-1), 2)) * pow(24, floordiv(-z, 2));
lon += scale * x;
lat += scale * y;
}
lon *= 2;
return {lat, lon};
}
// convert an arbitrary length grid locator to a high precision lat/lon in aprs format
QPair<QString, QString> APRSISClient::grid2aprs(QString grid){
auto geo = APRSISClient::grid2deg(grid);
auto lat = geo.first;
auto lon = geo.second;
QString latDir = "N";
if(lat < 0){
lat *= -1;
latDir = "S";
}
QString lonDir = "E";
if(lon < 0){
lon *= -1;
lonDir = "W";
}
double iLat, fLat, iLon, fLon, iLatMin, fLatMin, iLonMin, fLonMin, iLatSec, iLonSec;
fLat = modf(lat, &iLat);
fLon = modf(lon, &iLon);
fLatMin = modf(fLat * 60, &iLatMin);
fLonMin = modf(fLon * 60, &iLonMin);
iLatSec = round(fLatMin * 60);
iLonSec = round(fLonMin * 60);
if(iLatSec == 60){
iLatMin += 1;
iLatSec = 0;
}
if(iLonSec == 60){
iLonMin += 1;
iLonSec = 0;
}
if(iLatMin == 60){
iLat += 1;
iLatMin = 0;
}
if(iLonMin == 60){
iLon += 1;
iLonMin = 0;
}
double aprsLat = iLat * 100 + iLatMin + (iLatSec / 60.0);
double aprsLon = iLon * 100 + iLonMin + (iLonSec / 60.0);
return {
QString().sprintf("%07.2f%%1", aprsLat).arg(latDir),
QString().sprintf("%08.2f%%1", aprsLon).arg(lonDir)
};
}
void APRSISClient::enqueueSpot(QString theircall, QString grid, QString comment){
if(m_localCall.isEmpty()) return;
auto geo = APRSISClient::grid2aprs(grid);
auto spotFrame = QString("%1>%2,APRS,TCPIP*:=%3/%4nFT8CALL %5\n");
spotFrame = spotFrame.arg(theircall);
spotFrame = spotFrame.arg(m_localCall);
spotFrame = spotFrame.arg(geo.first);
spotFrame = spotFrame.arg(geo.second);
spotFrame = spotFrame.arg(comment.left(43));
enqueueRaw(spotFrame);
}
void APRSISClient::enqueueMessage(QString tocall, QString message){
if(m_localCall.isEmpty()) return;
auto messageFrame = QString("%1>APRS,TCPIP*::%2:%3\n");
messageFrame = messageFrame.arg(m_localCall);
messageFrame = messageFrame.arg(tocall + QString(" ").repeated(9-tocall.length()));
messageFrame = messageFrame.arg(message);
enqueueRaw(messageFrame);
}
void APRSISClient::enqueueThirdParty(QString theircall, QString payload){
auto frame = QString("%1>%2,APRS,TCPIP*:%3\n");
frame = frame.arg(theircall);
frame = frame.arg(m_localCall);
frame = frame.arg(payload);
enqueueRaw(frame);
}
void APRSISClient::enqueueRaw(QString aprsFrame){
m_frameQueue.enqueue(aprsFrame);
}
void APRSISClient::processQueue(bool disconnect){
// don't process queue if we haven't set our local callsign
if(m_localCall.isEmpty()) return;
// don't process queue if there's nothing to process
if(m_frameQueue.isEmpty()) return;
// 1. connect (and read)
// 2. login (and read)
// 3. for each raw frame in queue, send
// 4. disconnect
if(state() != QTcpSocket::ConnectedState){
connectToHost(m_host, m_port);
if(!waitForConnected(5000)){
qDebug() << "APRSISClient Connection Error:" << errorString();
return;
}
}
auto re = QRegExp("(full|unavailable|busy)");
auto line = QString(readLine());
if(line.toLower().indexOf(re) >= 0){
qDebug() << "APRSISClient Connection Busy:" << line;
return;
}
if(write(loginFrame(m_localCall).toLocal8Bit()) == -1){
qDebug() << "APRSISClient Write Login Error:" << errorString();
return;
}
if(!waitForReadyRead(5000)){
qDebug() << "APRSISClient Login Error: Server Not Responding";
return;
}
line = QString(readAll());
if(line.toLower().indexOf(re) >= 0){
qDebug() << "APRSISClient Server Busy:" << line;
return;
}
while(!m_frameQueue.isEmpty()){
QByteArray data = m_frameQueue.head().toLocal8Bit();
if(write(data) == -1){
qDebug() << "APRSISClient Write Error:" << errorString();
return;
}
if(!waitForBytesWritten(5000)){
qDebug() << "APRSISClient Cannot Write Error: Write Timeout";
return;
}
qDebug() << "APRSISClient Write:" << data;
if(waitForReadyRead(5000)){
line = QString(readLine());
qDebug() << "APRSISClient Read:" << line;
if(line.toLower().indexOf(re) >= 0){
qDebug() << "APRSISClient Cannot Write Error:" << line;
return;
}
}
m_frameQueue.dequeue();
}
if(disconnect){
disconnectFromHost();
}
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef APRSISCLIENT_H
#define APRSISCLIENT_H
#include <QTcpSocket>
#include <QQueue>
#include <QPair>
#include <QTimer>
class APRSISClient : public QTcpSocket
{
public:
APRSISClient(QString host, quint16 port, QObject *parent = nullptr);
static quint32 hashCallsign(QString callsign);
static QString loginFrame(QString callsign);
static QPair<float, float> grid2deg(QString grid);
static QPair<QString, QString> grid2aprs(QString grid);
void setLocalStation(QString mycall, QString mygrid){
m_localCall = mycall;
m_localGrid = mygrid;
}
void enqueueSpot(QString theircall, QString grid, QString comment);
void enqueueMessage(QString tocall, QString message);
void enqueueThirdParty(QString theircall, QString payload);
void enqueueRaw(QString aprsFrame);
void processQueue(bool disconnect=true);
public slots:
void sendReports(){ processQueue(true); }
private:
QString m_localCall;
QString m_localGrid;
QQueue<QString> m_frameQueue;
QString m_host;
quint16 m_port;
QTimer m_timer;
};
#endif // APRSISCLIENT_H
+2
View File
@@ -304,6 +304,8 @@ set (wsjtx_CXXSRCS
messageaveraging.cpp
WsprTxScheduler.cpp
varicode.cpp
SelfDestructMessageBox.cpp
APRSISClient.cpp
mainwindow.cpp
Configuration.cpp
main.cpp
+96 -80
View File
@@ -196,11 +196,14 @@ namespace
int const combo_box_item_disabled (0);
// QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"};
QRegExp message_alphabet {"[^\\x00-\\x1F]*"};
// Magic numbers for file validation
constexpr quint32 qrg_magic {0xadbccbdb};
constexpr quint32 qrg_version {100}; // M.mm
constexpr quint32 qrg_version {102}; // M.mm
// Bump this versioned key every time we need to "reset" our working frequencies...
const char * versionedFrequenciesSettingsKey = "FrequenciesForRegionModes_01";
}
@@ -451,6 +454,7 @@ private:
Q_SLOT void on_PTT_method_button_group_buttonClicked (int);
Q_SLOT void on_station_message_line_edit_textChanged(QString const&);
Q_SLOT void on_qth_message_line_edit_textChanged(QString const&);
Q_SLOT void on_reply_message_line_edit_textChanged(QString const&);
Q_SLOT void on_add_macro_line_edit_editingFinished ();
Q_SLOT void delete_macro ();
void delete_selected_macros (QModelIndexList);
@@ -551,16 +555,17 @@ private:
QString my_callsign_;
QString my_grid_;
QString my_station_;
int my_dBm_;
QString aprs_ssid_;
QString my_qth_;
QString reply_;
int callsign_aging_;
int activity_aging_;
QColor color_CQ_;
QColor next_color_CQ_;
QColor color_MyCall_;
QColor next_color_MyCall_;
QColor color_TxMsg_;
QColor next_color_TxMsg_;
QColor color_ReceivedMsg_;
QColor next_color_ReceivedMsg_;
QColor color_DXCC_;
QColor next_color_DXCC_;
QColor color_NewCall_;
@@ -573,11 +578,12 @@ private:
double txDelay_;
bool id_after_73_;
bool tx_QSY_allowed_;
bool spot_to_psk_reporter_;
bool spot_to_reporting_networks_;
bool transmit_directed_;
bool autoreply_off_at_startup_;
bool monitor_off_at_startup_;
bool monitor_last_used_;
bool log_as_RTTY_;
bool log_as_DATA_;
bool report_in_comments_;
bool prompt_to_log_;
bool insert_blank_;
@@ -612,6 +618,7 @@ private:
bool accept_udp_requests_;
bool udpWindowToFront_;
bool udpWindowRestore_;
bool udpEnabled_;
DataMode data_mode_;
bool pwrBandTxMemory_;
bool pwrBandTuneMemory_;
@@ -660,7 +667,7 @@ bool Configuration::use_dynamic_grid() const {return m_->use_dynamic_info_; }
QString Configuration::my_callsign () const {return m_->my_callsign_;}
QColor Configuration::color_CQ () const {return m_->color_CQ_;}
QColor Configuration::color_MyCall () const {return m_->color_MyCall_;}
QColor Configuration::color_TxMsg () const {return m_->color_TxMsg_;}
QColor Configuration::color_ReceivedMsg () const {return m_->color_ReceivedMsg_;}
QColor Configuration::color_DXCC () const {return m_->color_DXCC_;}
QColor Configuration::color_NewCall () const {return m_->color_NewCall_;}
QFont Configuration::text_font () const {return m_->font_;}
@@ -673,23 +680,24 @@ double Configuration::txDelay() const {return m_->txDelay_;}
qint32 Configuration::RxBandwidth() const {return m_->RxBandwidth_;}
bool Configuration::id_after_73 () const {return m_->id_after_73_;}
bool Configuration::tx_QSY_allowed () const {return m_->tx_QSY_allowed_;}
bool Configuration::spot_to_psk_reporter () const
bool Configuration::spot_to_reporting_networks () const
{
// rig must be open and working to spot externally
return is_transceiver_online () && m_->spot_to_psk_reporter_;
return is_transceiver_online () && m_->spot_to_reporting_networks_;
}
void Configuration::set_spot_to_psk_reporter (bool spot)
void Configuration::set_spot_to_reporting_networks (bool spot)
{
if(m_->spot_to_psk_reporter_ != spot){
m_->spot_to_psk_reporter_ = spot;
if(m_->spot_to_reporting_networks_ != spot){
m_->spot_to_reporting_networks_ = spot;
m_->write_settings();
}
}
bool Configuration::transmit_directed() const { return m_->transmit_directed_; }
bool Configuration::autoreply_off_at_startup () const {return m_->autoreply_off_at_startup_;}
bool Configuration::monitor_off_at_startup () const {return m_->monitor_off_at_startup_;}
bool Configuration::monitor_last_used () const {return m_->rig_is_dummy_ || m_->monitor_last_used_;}
bool Configuration::log_as_RTTY () const {return m_->log_as_RTTY_;}
bool Configuration::log_as_DATA () const {return m_->log_as_DATA_;}
bool Configuration::report_in_comments () const {return m_->report_in_comments_;}
bool Configuration::prompt_to_log () const {return m_->prompt_to_log_;}
bool Configuration::insert_blank () const {return m_->insert_blank_;}
@@ -720,6 +728,7 @@ auto Configuration::n1mm_server_port () const -> port_type {return m_->n1mm_serv
bool Configuration::broadcast_to_n1mm () const {return m_->broadcast_to_n1mm_;}
bool Configuration::udpWindowToFront () const {return m_->udpWindowToFront_;}
bool Configuration::udpWindowRestore () const {return m_->udpWindowRestore_;}
bool Configuration::udpEnabled () const {return m_->udpEnabled_;}
Bands * Configuration::bands () {return &m_->bands_;}
Bands const * Configuration::bands () const {return &m_->bands_;}
StationList * Configuration::stations () {return &m_->stations_;}
@@ -856,8 +865,8 @@ QString Configuration::my_station() const
return station;
}
int Configuration::my_dBm() const {
return m_->my_dBm_;
QString Configuration::aprs_ssid() const {
return m_->aprs_ssid_;
}
QString Configuration::my_qth() const
@@ -865,6 +874,11 @@ QString Configuration::my_qth() const
return m_->my_qth_;
}
QString Configuration::reply() const
{
return m_->reply_;
}
int Configuration::callsign_aging() const
{
return m_->callsign_aging_;
@@ -987,6 +1001,15 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
throw std::runtime_error {"Failed to create samples directory"};
}
QString messages_dir {"messages"};
if (!default_save_directory_.mkpath (messages_dir))
{
MessageBox::critical_message (this, tr ("Failed to create messages directory"),
tr ("path: \"%1\"")
.arg (default_save_directory_.absoluteFilePath (messages_dir)));
throw std::runtime_error {"Failed to create messages directory"};
}
// copy in any new sample files to the sample directory
QDir dest_dir {default_save_directory_};
dest_dir.cd (samples_dir);
@@ -1012,10 +1035,11 @@ Configuration::impl::impl (Configuration * self, QDir const& temp_directory,
// validation
//
ui_->callsign_line_edit->setValidator (new CallsignValidator {this});
ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {this});
ui_->grid_line_edit->setValidator (new MaidenheadLocatorValidator {this, MaidenheadLocatorValidator::Length::doubleextended});
ui_->add_macro_line_edit->setValidator (new QRegExpValidator {message_alphabet, this});
ui_->station_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_->udp_server_port_spin_box->setMinimum (1);
ui_->udp_server_port_spin_box->setMaximum (std::numeric_limits<port_type>::max ());
@@ -1197,53 +1221,20 @@ void Configuration::impl::initialize_models ()
pal.setColor (QPalette::Base, Qt::white);
}
QMap<int, int> dbm2mw = {
{0 , 1},
{3 , 2},
{7 , 5},
{10 , 10},
{13 , 20},
{17 , 50},
{20 , 100},
{23 , 200},
{27 , 500},
{30 , 1000}, // 1W
{33 , 2000}, // 2W
{37 , 5000}, // 5W
{40 , 10000}, // 10W
{43 , 20000}, // 20W
{47 , 50000}, // 50W
{50 , 100000}, // 100W
{53 , 200000}, // 200W
{57 , 500000}, // 500W
{60 , 1000000}, // 1000W
};
ui_->station_power_combo_box->clear();
ui_->station_power_combo_box->addItem(QString(""), -1);
foreach(auto dbm, dbm2mw.keys()){
ui_->station_power_combo_box->addItem(QString("%1 (%2 dBm)").arg(Varicode::formatPWR(dbm)).arg(dbm), dbm);
if(dbm == my_dBm_){
ui_->station_power_combo_box->setCurrentIndex(ui_->station_power_combo_box->count()-1);
}
}
ui_->callsign_line_edit->setPalette (pal);
ui_->grid_line_edit->setPalette (pal);
ui_->auto_switch_bands_check_box->setChecked(auto_switch_bands_);
ui_->callsign_line_edit->setText (my_callsign_);
ui_->grid_line_edit->setText (my_grid_);
ui_->grid_line_edit->setText (my_grid_.toUpper());
ui_->callsign_aging_spin_box->setValue(callsign_aging_);
ui_->activity_aging_spin_box->setValue(activity_aging_);
ui_->station_message_line_edit->setText (my_station_.toUpper());
ui_->qth_message_line_edit->setText (my_qth_.toUpper());
ui_->reply_message_line_edit->setText (reply_.toUpper());
ui_->use_dynamic_grid->setChecked(use_dynamic_info_);
ui_->labCQ->setStyleSheet(QString("background: %1").arg(color_CQ_.name()));
ui_->labMyCall->setStyleSheet(QString("background: %1").arg(color_MyCall_.name()));
ui_->labTx->setStyleSheet(QString("background: %1").arg(color_TxMsg_.name()));
ui_->labTx->setStyleSheet(QString("background: %1").arg(color_ReceivedMsg_.name()));
ui_->labDXCC->setStyleSheet(QString("background: %1").arg(color_DXCC_.name()));
ui_->labNewCall->setStyleSheet(QString("background: %1").arg(color_NewCall_.name()));
ui_->CW_id_interval_spin_box->setValue (id_interval_);
@@ -1257,11 +1248,12 @@ void Configuration::impl::initialize_models ()
ui_->azel_path_display_label->setText (azel_directory_.absolutePath ());
ui_->CW_id_after_73_check_box->setChecked (id_after_73_);
ui_->tx_QSY_check_box->setChecked (tx_QSY_allowed_);
ui_->psk_reporter_check_box->setChecked (spot_to_psk_reporter_);
ui_->psk_reporter_check_box->setChecked (spot_to_reporting_networks_);
ui_->transmit_directed_check_box->setChecked(transmit_directed_);
ui_->autoreply_off_check_box->setChecked (autoreply_off_at_startup_);
ui_->monitor_off_check_box->setChecked (monitor_off_at_startup_);
ui_->monitor_last_used_check_box->setChecked (monitor_last_used_);
ui_->log_as_RTTY_check_box->setChecked (log_as_RTTY_);
ui_->log_as_RTTY_check_box->setChecked (log_as_DATA_);
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_);
@@ -1319,6 +1311,7 @@ void Configuration::impl::initialize_models ()
ui_->n1mm_server_port_spin_box->setValue (n1mm_server_port_);
ui_->enable_n1mm_broadcast_check_box->setChecked (broadcast_to_n1mm_);
ui_->udpWindowToFront->setChecked(udpWindowToFront_);
ui_->udpEnable->setChecked(udpEnabled_);
ui_->udpWindowRestore->setChecked(udpWindowRestore_);
ui_->calibration_intercept_spin_box->setValue (calibration_.intercept);
ui_->calibration_slope_ppm_spin_box->setValue (calibration_.slope_ppm);
@@ -1363,13 +1356,14 @@ void Configuration::impl::read_settings ()
my_callsign_ = settings_->value ("MyCall", QString {}).toString ();
my_grid_ = settings_->value ("MyGrid", QString {}).toString ();
my_station_ = settings_->value("MyStation", QString {}).toString();
my_dBm_ = settings_->value("MyPower", -1).toInt();
aprs_ssid_ = settings_->value("APRSSSID", "-0").toString();
callsign_aging_ = settings_->value ("CallsignAging", 0).toInt ();
activity_aging_ = settings_->value ("ActivityAging", 2).toInt ();
my_qth_ = settings_->value("MyQTH", QString {}).toString();
reply_ = settings_->value("Reply", QString {"HW CPY?"}).toString();
next_color_CQ_ = color_CQ_ = settings_->value("colorCQ","#66ff66").toString();
next_color_MyCall_ = color_MyCall_ = settings_->value("colorMyCall","#ff6666").toString();
next_color_TxMsg_ = color_TxMsg_ = settings_->value("colorTxMsg","#ffff00").toString();
next_color_ReceivedMsg_ = color_ReceivedMsg_ = settings_->value("colorReceivedMsg","#ffeaa7").toString();
next_color_DXCC_ = color_DXCC_ = settings_->value("colorDXCC","#ff00ff").toString();
next_color_NewCall_ = color_NewCall_ = settings_->value("colorNewCall","#ffaaff").toString();
@@ -1460,10 +1454,11 @@ void Configuration::impl::read_settings ()
type_2_msg_gen_ = settings_->value ("Type2MsgGen", QVariant::fromValue (Configuration::type_2_msg_3_full)).value<Configuration::Type2MsgGen> ();
transmit_directed_ = settings_->value ("TransmitDirected", true).toBool();
autoreply_off_at_startup_ = settings_->value ("AutoreplyOFF", false).toBool ();
monitor_off_at_startup_ = settings_->value ("MonitorOFF", false).toBool ();
monitor_last_used_ = settings_->value ("MonitorLastUsed", false).toBool ();
spot_to_psk_reporter_ = settings_->value ("PSKReporter", false).toBool ();
spot_to_reporting_networks_ = settings_->value ("PSKReporter", true).toBool ();
id_after_73_ = settings_->value ("After73", false).toBool ();
tx_QSY_allowed_ = settings_->value ("TxQSYAllowed", false).toBool ();
use_dynamic_info_ = settings_->value ("AutoGrid", false).toBool ();
@@ -1474,9 +1469,9 @@ void Configuration::impl::read_settings ()
region_ = settings_->value ("Region", QVariant::fromValue (IARURegions::ALL)).value<IARURegions::Region> ();
if (settings_->contains ("FrequenciesForRegionModes"))
if (settings_->contains (versionedFrequenciesSettingsKey))
{
auto const& v = settings_->value ("FrequenciesForRegionModes");
auto const& v = settings_->value (versionedFrequenciesSettingsKey);
if (v.isValid ())
{
frequencies_.frequency_list (v.value<FrequencyList_v2::FrequencyItems> ());
@@ -1493,7 +1488,7 @@ void Configuration::impl::read_settings ()
stations_.station_list (settings_->value ("stations").value<StationList::Stations> ());
log_as_RTTY_ = settings_->value ("toRTTY", false).toBool ();
log_as_DATA_ = settings_->value ("toRTTY", false).toBool ();
report_in_comments_ = settings_->value("dBtoComments", false).toBool ();
rig_params_.rig_name = settings_->value ("Rig", TransceiverFactory::basic_transceiver_name_).toString ();
rig_is_dummy_ = TransceiverFactory::basic_transceiver_name_ == rig_params_.rig_name;
@@ -1520,7 +1515,7 @@ void Configuration::impl::read_settings ()
miles_ = settings_->value ("Miles", false).toBool ();
quick_call_ = settings_->value ("QuickCall", false).toBool ();
disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool ();
beacon_ = settings_->value ("TxBeacon", 15).toInt ();
beacon_ = settings_->value ("TxBeacon", 30).toInt ();
watchdog_ = settings_->value ("TxWatchdog", 0).toInt ();
TX_messages_ = settings_->value ("Tx2QSO", true).toBool ();
enable_VHF_features_ = settings_->value("VHFUHF",false).toBool ();
@@ -1540,6 +1535,7 @@ void Configuration::impl::read_settings ()
n1mm_server_port_ = settings_->value ("N1MMServerPort", 2333).toUInt ();
broadcast_to_n1mm_ = settings_->value ("BroadcastToN1MM", false).toBool ();
accept_udp_requests_ = settings_->value ("AcceptUDPRequests", false).toBool ();
udpEnabled_ = settings_->value("UDPEnabled", false).toBool();
udpWindowToFront_ = settings_->value ("udpWindowToFront",false).toBool ();
udpWindowRestore_ = settings_->value ("udpWindowRestore",false).toBool ();
calibration_.intercept = settings_->value ("CalibrationIntercept", 0.).toDouble ();
@@ -1556,13 +1552,14 @@ void Configuration::impl::write_settings ()
settings_->setValue ("MyCall", my_callsign_);
settings_->setValue ("MyGrid", my_grid_);
settings_->setValue ("MyStation", my_station_);
settings_->setValue ("MyPower", my_dBm_);
settings_->setValue ("APRSSSID", aprs_ssid_);
settings_->setValue ("MyQTH", my_qth_);
settings_->setValue ("Reply", reply_);
settings_->setValue ("CallsignAging", callsign_aging_);
settings_->setValue ("ActivityAging", activity_aging_);
settings_->setValue("colorCQ",color_CQ_);
settings_->setValue("colorMyCall",color_MyCall_);
settings_->setValue("colorTxMsg",color_TxMsg_);
settings_->setValue("colorReceivedMsg",color_ReceivedMsg_);
settings_->setValue("colorDXCC",color_DXCC_);
settings_->setValue("colorNewCall",color_NewCall_);
settings_->setValue ("Font", font_.toString ());
@@ -1598,16 +1595,17 @@ void Configuration::impl::write_settings ()
settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_));
settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_));
settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_));
settings_->setValue ("TransmitDirected", transmit_directed_);
settings_->setValue ("AutoreplyOFF", autoreply_off_at_startup_);
settings_->setValue ("MonitorOFF", monitor_off_at_startup_);
settings_->setValue ("MonitorLastUsed", monitor_last_used_);
settings_->setValue ("PSKReporter", spot_to_psk_reporter_);
settings_->setValue ("PSKReporter", spot_to_reporting_networks_);
settings_->setValue ("After73", id_after_73_);
settings_->setValue ("TxQSYAllowed", tx_QSY_allowed_);
settings_->setValue ("Macros", macros_.stringList ());
settings_->setValue ("FrequenciesForRegionModes", QVariant::fromValue (frequencies_.frequency_list ()));
settings_->setValue (versionedFrequenciesSettingsKey, QVariant::fromValue (frequencies_.frequency_list ()));
settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ()));
settings_->setValue ("toRTTY", log_as_RTTY_);
settings_->setValue ("toRTTY", log_as_DATA_);
settings_->setValue ("dBtoComments", report_in_comments_);
settings_->setValue ("Rig", rig_params_.rig_name);
settings_->setValue ("CATNetworkPort", rig_params_.network_port);
@@ -1651,6 +1649,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("N1MMServerPort", n1mm_server_port_);
settings_->setValue ("BroadcastToN1MM", broadcast_to_n1mm_);
settings_->setValue ("AcceptUDPRequests", accept_udp_requests_);
settings_->setValue ("UDPEnabled", udpEnabled_);
settings_->setValue ("udpWindowToFront", udpWindowToFront_);
settings_->setValue ("udpWindowRestore", udpWindowRestore_);
settings_->setValue ("CalibrationIntercept", calibration_.intercept);
@@ -1928,10 +1927,12 @@ void Configuration::impl::accept ()
color_CQ_ = next_color_CQ_;
color_MyCall_ = next_color_MyCall_;
color_TxMsg_ = next_color_TxMsg_;
color_ReceivedMsg_ = next_color_ReceivedMsg_;
color_DXCC_ = next_color_DXCC_;
color_NewCall_ = next_color_NewCall_;
Q_EMIT self_->colors_changed();
rig_params_ = temp_rig_params; // now we can go live with the rig
// related configuration parameters
rig_is_dummy_ = TransceiverFactory::basic_transceiver_name_ == rig_params_.rig_name;
@@ -2014,11 +2015,12 @@ void Configuration::impl::accept ()
my_callsign_ = ui_->callsign_line_edit->text ();
my_grid_ = ui_->grid_line_edit->text ();
my_station_ = ui_->station_message_line_edit->text().toUpper();
my_dBm_ = ui_->station_power_combo_box->currentData().toInt();
reply_ = ui_->reply_message_line_edit->text().toUpper();
aprs_ssid_ = ui_->aprs_ssid_line_edit->text().toUpper();
my_qth_ = ui_->qth_message_line_edit->text().toUpper();
callsign_aging_ = ui_->callsign_aging_spin_box->value();
activity_aging_ = ui_->activity_aging_spin_box->value();
spot_to_psk_reporter_ = ui_->psk_reporter_check_box->isChecked ();
spot_to_reporting_networks_ = ui_->psk_reporter_check_box->isChecked ();
id_interval_ = ui_->CW_id_interval_spin_box->value ();
ntrials_ = ui_->sbNtrials->value ();
txDelay_ = ui_->sbTxDelay->value ();
@@ -2027,11 +2029,12 @@ void Configuration::impl::accept ()
RxBandwidth_ = ui_->sbBandwidth->value ();
id_after_73_ = ui_->CW_id_after_73_check_box->isChecked ();
tx_QSY_allowed_ = ui_->tx_QSY_check_box->isChecked ();
transmit_directed_ = ui_->transmit_directed_check_box->isChecked();
autoreply_off_at_startup_ = ui_->autoreply_off_check_box->isChecked ();
monitor_off_at_startup_ = ui_->monitor_off_check_box->isChecked ();
monitor_last_used_ = ui_->monitor_last_used_check_box->isChecked ();
type_2_msg_gen_ = static_cast<Type2MsgGen> (ui_->type_2_msg_gen_combo_box->currentIndex ());
log_as_RTTY_ = 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 ();
prompt_to_log_ = ui_->prompt_to_log_check_box->isChecked ();
insert_blank_ = ui_->insert_blank_check_box->isChecked ();
@@ -2060,11 +2063,15 @@ void Configuration::impl::accept ()
pwrBandTxMemory_ = ui_->checkBoxPwrBandTxMemory->isChecked ();
pwrBandTuneMemory_ = ui_->checkBoxPwrBandTuneMemory->isChecked ();
opCall_=ui_->opCallEntry->text();
auto newUdpEnabled = ui_->udpEnable->isChecked();
auto new_server = ui_->udp_server_line_edit->text ();
if (new_server != udp_server_name_)
if (new_server != udp_server_name_ || newUdpEnabled != udpEnabled_)
{
udp_server_name_ = new_server;
Q_EMIT self_->udp_server_changed (new_server);
udpEnabled_ = newUdpEnabled;
Q_EMIT self_->udp_server_changed (udpEnabled_ ? new_server : "");
}
auto new_port = ui_->udp_server_port_spin_box->value ();
@@ -2073,7 +2080,7 @@ void Configuration::impl::accept ()
udp_server_port_ = new_port;
Q_EMIT self_->udp_server_port_changed (new_port);
}
accept_udp_requests_ = ui_->accept_udp_requests_check_box->isChecked ();
auto new_n1mm_server = ui_->n1mm_server_name_line_edit->text ();
n1mm_server_name_ = new_n1mm_server;
@@ -2084,6 +2091,7 @@ void Configuration::impl::accept ()
udpWindowToFront_ = ui_->udpWindowToFront->isChecked ();
udpWindowRestore_ = ui_->udpWindowRestore->isChecked ();
if (macros_.stringList () != next_macros_.stringList ())
{
macros_.setStringList (next_macros_.stringList ());
@@ -2145,7 +2153,7 @@ void Configuration::impl::on_font_push_button_clicked ()
void Configuration::impl::on_pbCQmsg_clicked()
{
auto new_color = QColorDialog::getColor(next_color_CQ_, this, "CQ Messages Color");
auto new_color = QColorDialog::getColor(next_color_CQ_, this, "CQ and BEACON Messages Color");
if (new_color.isValid ())
{
next_color_CQ_ = new_color;
@@ -2155,7 +2163,7 @@ void Configuration::impl::on_pbCQmsg_clicked()
void Configuration::impl::on_pbMyCall_clicked()
{
auto new_color = QColorDialog::getColor(next_color_MyCall_, this, "My Call Messages Color");
auto new_color = QColorDialog::getColor(next_color_MyCall_, this, "Directed Messages Color");
if (new_color.isValid ())
{
next_color_MyCall_ = new_color;
@@ -2165,11 +2173,11 @@ void Configuration::impl::on_pbMyCall_clicked()
void Configuration::impl::on_pbTxMsg_clicked()
{
auto new_color = QColorDialog::getColor(next_color_TxMsg_, this, "Tx Messages Color");
auto new_color = QColorDialog::getColor(next_color_ReceivedMsg_, this, "Received Messages Textarea Color");
if (new_color.isValid ())
{
next_color_TxMsg_ = new_color;
ui_->labTx->setStyleSheet(QString("background: %1").arg(next_color_TxMsg_.name()));
next_color_ReceivedMsg_ = new_color;
ui_->labTx->setStyleSheet(QString("background: %1").arg(next_color_ReceivedMsg_.name()));
}
}
@@ -2196,7 +2204,7 @@ void Configuration::impl::on_pbNewCall_clicked()
void Configuration::impl::on_decoded_text_font_push_button_clicked ()
{
next_decoded_text_font_ = QFontDialog::getFont (0, decoded_text_font_ , this
, tr ("WSJT-X Decoded Text Font Chooser")
, tr ("Font Chooser")
#if QT_VERSION >= 0x050201
, QFontDialog::MonospacedFonts
#endif
@@ -2320,6 +2328,14 @@ void Configuration::impl::on_qth_message_line_edit_textChanged(QString const &te
}
}
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 ()
{
ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ());
+9 -5
View File
@@ -98,10 +98,11 @@ public:
QString my_callsign () const;
QString my_grid () const;
QString my_station () const;
int my_dBm() const;
QString aprs_ssid() const;
int activity_aging() const;
int callsign_aging() const;
QString my_qth () const;
QString reply () const;
QFont text_font () const;
QFont decoded_text_font () const;
qint32 id_interval () const;
@@ -112,12 +113,13 @@ public:
double txDelay() const;
bool id_after_73 () const;
bool tx_QSY_allowed () const;
bool spot_to_psk_reporter () const;
void set_spot_to_psk_reporter (bool);
bool spot_to_reporting_networks () const;
void set_spot_to_reporting_networks (bool);
bool transmit_directed() const;
bool autoreply_off_at_startup () const;
bool monitor_off_at_startup () const;
bool monitor_last_used () const;
bool log_as_RTTY () const;
bool log_as_DATA () const;
bool report_in_comments () const;
bool prompt_to_log () const;
bool insert_blank () const;
@@ -156,6 +158,7 @@ public:
bool accept_udp_requests () const;
bool udpWindowToFront () const;
bool udpWindowRestore () const;
bool udpEnabled () const;
Bands * bands ();
Bands const * bands () const;
IARURegions::Region region () const;
@@ -172,7 +175,7 @@ public:
Type2MsgGen type_2_msg_gen () const;
QColor color_CQ () const;
QColor color_MyCall () const;
QColor color_TxMsg () const;
QColor color_ReceivedMsg () const;
QColor color_DXCC () const;
QColor color_NewCall () const;
bool pwrBandTxMemory () const;
@@ -267,6 +270,7 @@ public:
//
Q_SIGNAL void text_font_changed (QFont);
Q_SIGNAL void decoded_text_font_changed (QFont);
Q_SIGNAL void colors_changed ();
//
// This signal is emitted when the UDP server changes
+531 -469
View File
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -26,16 +26,16 @@ namespace
{
FrequencyList_v2::FrequencyItems const default_frequency_list =
{
{ 1838000, Modes::FT8CALL, IARURegions::ALL}, // 2 below
{ 3580000, Modes::FT8CALL, IARURegions::ALL}, // 7 above
{ 7080000, Modes::FT8CALL, IARURegions::ALL}, // 7 above
{ 1842000, Modes::FT8CALL, IARURegions::ALL}, // 2 above
{ 3578000, Modes::FT8CALL, IARURegions::ALL}, // 5 above
{ 7078000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{10130000, Modes::FT8CALL, IARURegions::ALL}, // 6 below
{14080000, Modes::FT8CALL, IARURegions::ALL}, // 6 above
{14078000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{18104000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{21080000, Modes::FT8CALL, IARURegions::ALL}, // 6 above
{24920000, Modes::FT8CALL, IARURegions::ALL}, // 5 above
{28080000, Modes::FT8CALL, IARURegions::ALL}, // 6 above
{50300000, Modes::FT8CALL, IARURegions::ALL}, // 13 below
{21078000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{24922000, Modes::FT8CALL, IARURegions::ALL}, // 9 above
{28078000, Modes::FT8CALL, IARURegions::ALL}, // 4 above
{50318000, Modes::FT8CALL, IARURegions::ALL}, // 5 above
};
}
+1 -1
View File
@@ -11,7 +11,7 @@ class MaidenheadLocatorValidator final
: public QValidator
{
public:
enum class Length {field = 2, square = 4, subsquare = 6, extended = 8};
enum class Length {field = 2, square = 4, subsquare = 6, extended = 8, doubleextended = 16};
MaidenheadLocatorValidator (QObject * parent = nullptr
, Length length = Length::subsquare
, Length required = Length::square);
+1
View File
@@ -329,6 +329,7 @@ auto MessageClient::server_port () const -> port_type
void MessageClient::set_server (QString const& server)
{
qDebug() << "server changed to" << server;
m_->server_.clear ();
m_->server_string_ = server;
if (!server.isEmpty ())
+40
View File
@@ -0,0 +1,40 @@
#include "SelfDestructMessageBox.h"
SelfDestructMessageBox::SelfDestructMessageBox(
int timeout,
const QString& title,
const QString& text,
QMessageBox::Icon icon,
QMessageBox::StandardButtons buttons,
QMessageBox::StandardButton defaultButton,
QWidget* parent,
Qt::WindowFlags flags)
: QMessageBox(icon, title, text, buttons, parent, flags),
m_timeout(timeout),
m_text(text)
{
connect(&m_timer, &QTimer::timeout, this, &SelfDestructMessageBox::tick);
m_timer.setInterval(1000);
setDefaultButton(defaultButton);
connect(this->defaultButton(), &QPushButton::clicked, this, &SelfDestructMessageBox::accept);
}
void SelfDestructMessageBox::showEvent(QShowEvent* event)
{
tick();
m_timer.start();
QMessageBox::showEvent(event);
}
void SelfDestructMessageBox::tick(){
m_timeout--;
if(m_timeout){
setText(m_text.arg(m_timeout));
return;
}
m_timer.stop();
accept();
}
+35
View File
@@ -0,0 +1,35 @@
#ifndef SELFDESTRUCTMESSAGEBOX_H
#define SELFDESTRUCTMESSAGEBOX_H
#include <QWidget>
#include <QMessageBox>
#include <QPushButton>
#include <QString>
#include <QTimer>
class SelfDestructMessageBox : public QMessageBox
{
Q_OBJECT
public:
SelfDestructMessageBox(int timeout,
const QString& title,
const QString& text,
QMessageBox::Icon icon,
QMessageBox::StandardButtons buttons = QMessageBox::Ok | QMessageBox::Cancel,
QMessageBox::StandardButton defaultButton = QMessageBox::Ok,
QWidget* parent = nullptr,
Qt::WindowFlags flags = 0);
void showEvent(QShowEvent* event) override;
private slots:
void tick();
private:
int m_timeout;
QString m_text;
QTimer m_timer;
};
#endif // SELFDESTRUCTMESSAGEBOX_H
+2 -2
View File
@@ -1,6 +1,6 @@
# Version number components
set (WSJTX_VERSION_MAJOR 0)
set (WSJTX_VERSION_MINOR 4)
set (WSJTX_VERSION_PATCH 2)
set (WSJTX_VERSION_MINOR 5)
set (WSJTX_VERSION_PATCH 1)
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
+69
View File
@@ -0,0 +1,69 @@
import socket
KKEY = 0x73e2
def do_hash(callsign):
rootCall = callsign.split("-")[0].upper() + '\0'
hash = KKEY
i = 0
length = len(rootCall)
while (i+1 < length):
hash ^= ord(rootCall[i])<<8
hash ^= ord(rootCall[i+1])
i += 2
return int(hash & 0x7fff)
HOST = 'rotate.aprs2.net'
PORT = 14580
print "Connecting..."
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
print "Connected..."
data = s.recv(1024)
print data
call = 'KN4CRD'
pw = do_hash(call)
ver = "FT8Call"
login = "user {} pass {} ver {}\n".format(call, pw, ver)
s.send(login)
print "Login sent...", login
data = s.recv(1024)
print data
if 0:
message = "KN4CRD>OH8STN,APRS,TCPIP*::EMAIL-2 :KN4CRD@GMAIL.COM TESTING!{04}\n"
s.send(message)
if 0:
message = "{}>APRS,TCPIP*::EMAIL-2 :kn4crd@gmail.com testing456{{01}}\n".format(call)
message = "KN4CRD>APRS,TCPIP*::EMAIL-2 :KN4CRD@GMAIL.COM TESTING!{02}\n"
s.send(message)
if 0:
payload = ":This is a test message"
message = "{}>APRS,TCPIP*::{} {}\n".format(call, call, payload)
s.send(message)
if 1:
position = "=3352.45N/08422.71Wn"
status = "FT8CALL VIA XX9XXX/XXXX 14.082500MHz -20dB"
payload = "".join((position, status))
message = "{}>OH8STN,APRS,TCPIP*:{}\n".format(call, payload)
s.send(message)
print "Spot sent...", message
data = s.recv(1024)
print data
s.close()
+2 -2
View File
@@ -277,7 +277,7 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
QColor color_TxMsg, bool bFastMode)
QColor color_ReceivedMsg, bool bFastMode)
{
QString t1=" @ ";
if(modeTx=="FT8") t1=" ~ ";
@@ -297,7 +297,7 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx
t = QDateTime::currentDateTimeUtc().toString("hhmm") + \
" Tx " + t2 + t1 + text;
}
appendText (t, color_TxMsg);
appendText (t, color_ReceivedMsg);
}
void DisplayText::displayQSY(QString text)
+1 -1
View File
@@ -26,7 +26,7 @@ public:
LogBook const& logBook, QColor color_CQ, QColor color_MyCall,
QColor color_DXCC, QColor color_NewCall, bool ppfx, bool bCQonly=false);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
QColor color_TxMsg, bool bFastMode);
QColor color_ReceivedMsg, bool bFastMode);
void displayQSY(QString text);
void displayFoxToBeCalled(QString t, QColor bg);
+1 -1
View File
@@ -75,7 +75,7 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString
if(rptRcvd!="") t+=" Rcvd: " + rptRcvd;
ui->comments->setText(t);
}
if(toRTTY) mode="RTTY";
if(toRTTY) mode="DATA";
ui->mode->setText(mode);
ui->sent->setText(rptSent);
ui->rcvd->setText(rptRcvd);
+1063 -323
View File
File diff suppressed because it is too large Load Diff
+34 -8
View File
@@ -44,6 +44,7 @@
#include "qpriorityqueue.h"
#include "varicode.h"
#include "MessageClient.hpp"
#include "APRSISClient.h"
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
@@ -132,14 +133,19 @@ public slots:
void logCallActivity(CallDetail d, bool spot=true);
QString lookupCallInCompoundCache(QString const &call);
void cacheActivity(QString key);
void restoreActivity(QString key);
void clearActivity();
void displayTextForFreq(QString text, int freq, QDateTime date, bool isTx, bool isNewLine, bool isLast);
void writeNoticeTextToUI(QDateTime date, QString text);
int writeMessageTextToUI(QDateTime date, QString text, int freq, bool bold, int block=-1);
void addMessageText(QString text, bool clear=false);
bool isMessageQueuedForTransmit();
void addMessageText(QString text, bool clear=false, bool selectFirstPlaceholder=false);
void enqueueMessage(int priority, QString message, int freq, Callback c);
void resetMessage();
void resetMessageUI();
void restoreMessage();
bool ensureCallsignSet(bool alert=true);
void createMessage(QString const& text);
void createMessageTransmitQueue(QString const& text);
void resetMessageTransmitQueue();
@@ -164,7 +170,7 @@ private slots:
void on_actionShow_Waterfall_triggered(bool checked);
void on_actionReset_Window_Sizes_triggered();
void on_actionSettings_triggered();
void preparePSKReporter();
void prepareSpotting();
void on_spotButton_clicked(bool checked);
void on_monitorButton_clicked (bool);
void on_actionAbout_triggered();
@@ -252,9 +258,14 @@ private slots:
void on_rbFreeText_clicked(bool checked);
void on_clearAction_triggered(QObject * sender);
void on_cqMacroButton_clicked();
void on_qtcMacroButton_clicked();
void on_replyMacroButton_clicked();
void on_qthMacroButton_clicked();
void buildQueryMenu(QMenu *);
void setSortBy(QString key, QString value);
QString getSortBy(QString key, QString defaultValue);
void buildSortByMenu(QMenu * menu, QString key, QString defaultValue, QList<QPair<QString, QString> > values);
void buildBandActivitySortByMenu(QMenu * menu);
void buildCallActivitySortByMenu(QMenu * menu);
void buildQueryMenu(QMenu *, QString callsign);
void on_queryButton_pressed();
void on_macrosMacroButton_pressed();
void on_tableWidgetRXAll_cellClicked(int row, int col);
@@ -277,7 +288,7 @@ private slots:
void pauseBacon();
void checkBacon();
void prepareBacon();
QString calculateDistance(QString const& grid);
QString calculateDistance(QString const& grid, int *pDistance=nullptr);
void on_rptSpinBox_valueChanged(int n);
void killFile();
void on_tuneButton_clicked (bool);
@@ -353,6 +364,7 @@ private slots:
void on_sbMax_dB_valueChanged(int n);
void on_pbFoxReset_clicked();
void on_comboBoxHoundSort_activated (int index);
void expiry_warning_message ();
void not_GA_warning_message ();
private:
@@ -722,6 +734,12 @@ private:
}
};
struct CachedDirectedType {
bool isAllcall;
QDateTime date;
};
QMap<QString, QVariant> m_sortCache; // table key -> sort by
QPriorityQueue<PrioritizedMessage> m_txMessageQueue; // messages to be sent
QQueue<QString> m_txFrameQueue; // frames to be sent
QQueue<ActivityDetail> m_rxActivityQueue; // all rx activity queue
@@ -730,12 +748,17 @@ private:
QMap<QString, QString> m_compoundCallCache; // base callsign -> compound callsign
QCache<QString, QDateTime> m_txAllcallCommandCache; // callsign -> last tx
QCache<int, QDateTime> m_rxRecentCache; // freq -> last rx
QCache<int, QDateTime> m_rxDirectedCache; // freq -> last directed rx
QCache<int, CachedDirectedType> m_rxDirectedCache; // freq -> last directed rx
QCache<QString, int> m_rxCallCache; // call -> last freq seen
QMap<int, int> m_rxFrameBlockNumbers; // freq -> block
QMap<int, QList<ActivityDetail>> m_bandActivity; // freq -> [(text, last timestamp), ...]
QMap<int, MessageBuffer> m_messageBuffer; // freq -> (cmd, [frames, ...])
QMap<QString, CallDetail> m_callActivity; // call -> (last freq, last timestamp)
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
QSet<QString> m_callSeenBeacon; // call
int m_previousFreq;
bool m_shouldRestoreFreq;
@@ -791,6 +814,7 @@ private:
QTimer m_heartbeat;
MessageClient * m_messageClient;
PSK_Reporter *psk_Reporter;
APRSISClient * m_aprsClient;
DisplayManual m_manual;
QHash<QString, QVariant> m_pwrBandTxMemory; // Remembers power level by band
QHash<QString, QVariant> m_pwrBandTuneMemory; // Remembers power level by band for tuning
@@ -817,8 +841,10 @@ private:
void transmit (double snr = 99.);
void rigFailure (QString const& reason);
void pskSetLocal ();
void aprsSetLocal ();
void pskPost(DecodedText const& decodedtext);
void pskLogReport(QString mode, int offset, int snr, QString callsign, QString grid);
void aprsLogReport(int offset, int snr, QString callsign, QString grid);
Radio::Frequency dialFrequency();
void displayDialFrequency ();
void transmitDisplay (bool);
@@ -834,8 +860,8 @@ private:
QString callsignSelected();
bool isRecentOffset(int offset);
void markOffsetRecent(int offset);
bool isDirectedOffset(int offset);
void markOffsetDirected(int offset);
bool isDirectedOffset(int offset, bool *pIsAllCall);
void markOffsetDirected(int offset, bool isAllCall);
void processActivity(bool force=false);
void processRxActivity();
void processCompoundActivity();
+69 -6
View File
@@ -221,7 +221,7 @@ QPushButton[oob=&quot;true&quot;] {
</string>
</property>
<property name="text">
<string>14.074 000</string>
<string>14.078 000</string>
</property>
<property name="flat">
<bool>true</bool>
@@ -508,6 +508,9 @@ color : white;
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable the receiver&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
font-family: helvetica;
@@ -640,6 +643,9 @@ background-color: yellow;
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Transmit a tuning tone&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
font-family: helvetica;
@@ -701,6 +707,9 @@ background-color: yellow;
<height>30</height>
</size>
</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="styleSheet">
<string notr="true">QPushButton {
font-family: helvetica;
@@ -761,6 +770,9 @@ background-color: #6699ff;
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable spotting of callsigns heard to PSKReporter&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
font-family: helvetica;
@@ -821,6 +833,9 @@ background-color: #00ff00;
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable or disable the automatic beacon&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
font-family: helvetica;
@@ -881,6 +896,9 @@ background-color: #6699ff;
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Insert a new entry into the log&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
font-family: helvetica;
@@ -951,6 +969,9 @@ background-color: #00ff00;
<pointsize>12</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Received band activity is displayed with time since last heard, SNR, and the text received for each frequency offset in the passband.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContentsOnFirstShow</enum>
</property>
@@ -1097,7 +1118,7 @@ QTextEdit[transmitting=&quot;true&quot;] {
<bool>false</bool>
</property>
<property name="placeholderText">
<string>Type your outgoing messages / commands here.</string>
<string>Type your outgoing messages here.</string>
</property>
</widget>
</widget>
@@ -1107,6 +1128,9 @@ QTextEdit[transmitting=&quot;true&quot;] {
<pointsize>12</pointsize>
</font>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Received callsigns are displayed with time since last heard, SNR, and grid locator (if reported).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="autoScroll">
<bool>false</bool>
</property>
@@ -1154,6 +1178,11 @@ QTextEdit[transmitting=&quot;true&quot;] {
<string>Callsign</string>
</property>
</column>
<column>
<property name="text">
<string>Offset</string>
</property>
</column>
<column>
<property name="text">
<string>Age</string>
@@ -1232,6 +1261,12 @@ QTextEdit[transmitting=&quot;true&quot;] {
<height>30</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;Send your station location message&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>QTH</string>
</property>
@@ -1245,6 +1280,9 @@ QTextEdit[transmitting=&quot;true&quot;] {
<height>30</height>
</size>
</property>
<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="text">
<string>CQ</string>
</property>
@@ -1261,24 +1299,27 @@ QTextEdit[transmitting=&quot;true&quot;] {
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Stop transmitting&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Halt</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="qtcMacroButton">
<widget class="QPushButton" name="replyMacroButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="visible">
<bool>true</bool>
<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>QTC</string>
<string>Reply</string>
</property>
</widget>
</item>
@@ -1290,6 +1331,9 @@ QTextEdit[transmitting=&quot;true&quot;] {
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Send a macro&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Macros</string>
</property>
@@ -1306,6 +1350,9 @@ QTextEdit[transmitting=&quot;true&quot;] {
<height>30</height>
</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>
</property>
<property name="styleSheet">
<string notr="true">QPushButton:checked {
background-color: #00ff00;
@@ -1330,6 +1377,9 @@ background:yellow;
<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>
@@ -4308,6 +4358,9 @@ list. The list can be maintained in Settings (F2).</string>
<property name="title">
<string>Window</string>
</property>
<addaction name="actionSort_Band_Activity"/>
<addaction name="actionSort_Call_Activity"/>
<addaction name="separator"/>
<addaction name="actionShow_Band_Activity"/>
<addaction name="actionShow_Call_Activity"/>
<addaction name="actionShow_Waterfall"/>
@@ -5003,6 +5056,16 @@ list. The list can be maintained in Settings (F2).</string>
<string>Reset Window Sizes</string>
</property>
</action>
<action name="actionSort_Band_Activity">
<property name="text">
<string>Sort Band Activity...</string>
</property>
</action>
<action name="actionSort_Call_Activity">
<property name="text">
<string>Sort Call Activity...</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
+79 -6
View File
@@ -40,7 +40,8 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
m_Percent2DScreen0 {0},
m_rxFreq {1020},
m_txFreq {0},
m_startFreq {0}
m_startFreq {0},
m_lastMouseX {-1}
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setFocusPolicy(Qt::StrongFocus);
@@ -50,6 +51,8 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
setAttribute(Qt::WA_NoSystemBackground, true);
m_bReplot=false;
setMouseTracking(true);
// contextual pop up menu
setContextMenuPolicy (Qt::CustomContextMenu);
connect (this, &QWidget::customContextMenuRequested, [this] (QPoint const& pos) {
@@ -91,8 +94,10 @@ void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent()
m_h1=m_h-m_h2;
// m_line=0;
m_FullOverlayPixmap = QPixmap(m_Size.width(), m_h);
m_FullOverlayPixmap.fill(Qt::transparent);
m_DialOverlayPixmap = QPixmap(m_Size.width(), m_h);
m_DialOverlayPixmap.fill(Qt::transparent);
m_HoverOverlayPixmap = QPixmap(m_Size.width(), m_h);
m_HoverOverlayPixmap.fill(Qt::transparent);
m_2DPixmap = QPixmap(m_Size.width(), m_h2);
m_2DPixmap.fill(Qt::black);
m_WaterfallPixmap = QPixmap(m_Size.width(), m_h1);
@@ -117,7 +122,12 @@ void CPlotter::paintEvent(QPaintEvent *) // paint
painter.drawPixmap(0,m_h1,m_2DPixmap);
int x = XfromFreq(m_rxFreq);
painter.drawPixmap(x,0,m_FullOverlayPixmap);
painter.drawPixmap(x,0,m_DialOverlayPixmap);
if(m_lastMouseX >= 0 && m_lastMouseX != x){
painter.drawPixmap(m_lastMouseX, 0, m_HoverOverlayPixmap);
}
m_paintEventBusy=false;
}
@@ -329,6 +339,7 @@ void CPlotter::DrawOverlay() //DrawOverlay()
QPen penOrange(QColor(255,165,0),3);
QPen penGreen(Qt::green, 3); //Mark Tol range with green line
QPen penRed(Qt::red, 3); //Mark Tx freq with red
QPen penYellow(QColor(243, 156, 18), 3); //Mark band block freq with this pen
QPainter painter(&m_OverlayPixmap);
painter.initFrom(this);
QLinearGradient gradient(0, 0, 0 ,m_h2); //fill background with gradient
@@ -396,7 +407,7 @@ void CPlotter::DrawOverlay() //DrawOverlay()
if(m_freqPerDiv==200) minor=4;
for( int i=1; i<minor*m_hdivs; i++) { //minor ticks
x = i*pixperdiv/minor;
painter0.drawLine(x,24,x,30);
painter0.drawLine(x,22,x,30);
}
//draw frequency values
@@ -557,9 +568,17 @@ void CPlotter::DrawOverlay() //DrawOverlay()
}
}
x1=XfromFreq(0);
x2=XfromFreq(500);
if(x1<=m_w and x2>0) {
painter0.setPen(penYellow); //Mark bottom of sub-band
painter0.drawLine(x1+1,26,x2-2,26);
painter0.drawLine(x1+1,28,x2-2,28);
}
if(m_mode=="FT8"){
int fwidth=XfromFreq(m_rxFreq+bw)-XfromFreq(m_rxFreq);
QPainter overPainter(&m_FullOverlayPixmap);
QPainter overPainter(&m_DialOverlayPixmap);
overPainter.initFrom(this);
overPainter.setCompositionMode(QPainter::CompositionMode_Source);
overPainter.fillRect(0, 0, m_Size.width(), m_h, Qt::transparent);
@@ -571,6 +590,20 @@ void CPlotter::DrawOverlay() //DrawOverlay()
overPainter.setPen(penRed);
overPainter.drawLine(0, 26, fwidth, 26);
overPainter.drawLine(0, 28, fwidth, 28);
QPainter hoverPainter(&m_HoverOverlayPixmap);
hoverPainter.initFrom(this);
hoverPainter.setCompositionMode(QPainter::CompositionMode_Source);
hoverPainter.fillRect(0, 0, m_Size.width(), m_h, Qt::transparent);
hoverPainter.setPen(QPen(Qt::white));
hoverPainter.drawLine(0, 30, 0, m_h);
hoverPainter.drawLine(fwidth+1, 30, fwidth+1, m_h);
#if DRAW_FREQ_OVERLAY
int f = FreqfromX(m_lastMouseX);
hoverPainter.setFont(Font);
hoverPainter.drawText(fwidth + 5, m_h, QString("%1").arg(f));
#endif
}
}
@@ -692,6 +725,46 @@ void CPlotter::setRxFreq (int x) //setRxFreq
int CPlotter::rxFreq() {return m_rxFreq;} //rxFreq
void CPlotter::leaveEvent(QEvent *event)
{
m_lastMouseX = -1;
}
void CPlotter::wheelEvent(QWheelEvent *event){
auto delta = event->angleDelta();
if(delta.isNull()){
event->ignore();
return;
}
int newFreq = rxFreq();
int dir = delta.y() > 0 ? 1 : -1;
bool ctrl = (event->modifiers() & Qt::ControlModifier);
if(ctrl){
newFreq += dir;
} else {
newFreq = newFreq/10*10 + dir*10;
}
emit setFreq1 (newFreq, newFreq);
}
void CPlotter::mouseMoveEvent (QMouseEvent * event)
{
int x = event->x();
if(x < 0) x = 0;
if(x>m_Size.width()) x = m_Size.width();
m_lastMouseX = x;
#if DRAW_FREQ_OVERLAY
DrawOverlay();
#endif
update();
event->ignore();
}
void CPlotter::mouseReleaseEvent (QMouseEvent * event)
{
if (Qt::LeftButton == event->button ()) {
+6 -1
View File
@@ -95,6 +95,9 @@ protected:
//re-implemented widget event handlers
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent* event) override;
void leaveEvent(QEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
void mouseMoveEvent(QMouseEvent * event) override;
void mouseReleaseEvent (QMouseEvent * event) override;
void mouseDoubleClickEvent (QMouseEvent * event) override;
@@ -128,7 +131,8 @@ private:
qint32 m_ia;
qint32 m_ib;
QPixmap m_FullOverlayPixmap;
QPixmap m_DialOverlayPixmap;
QPixmap m_HoverOverlayPixmap;
QPixmap m_WaterfallPixmap;
QPixmap m_2DPixmap;
QPixmap m_ScalePixmap;
@@ -174,6 +178,7 @@ private:
qint32 m_startFreq;
qint32 m_tol;
qint32 m_j;
qint32 m_lastMouseX;
char m_sutc[6];
};
+59 -92
View File
@@ -30,7 +30,7 @@
const int nalphabet = 41;
QString alphabet = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?"}; // alphabet to encode _into_ for FT8 freetext transmission
QString alphabet72 = {"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+/?."};
QString grid_pattern = {R"((?<grid>[A-R]{2}[0-9]{2})+)"};
QString grid_pattern = {R"((?<grid>[A-X]{2}[0-9]{2}(?:[A-X]{2}(?:[0-9]{2})?)*)+)"};
QString orig_compound_callsign_pattern = {R"((?<callsign>(\d|[A-Z])+\/?((\d|[A-Z]){2,})(\/(\d|[A-Z])+)?(\/(\d|[A-Z])+)?))"};
QString compound_callsign_pattern = {R"((?<callsign>\b(?<prefix>[A-Z0-9]{1,4}\/)?(?<base>([0-9A-Z])?([0-9A-Z])([0-9])([A-Z])?([A-Z])?([A-Z])?)(?<suffix>\/[A-Z0-9]{1,4})?)\b)"};
QString pack_callsign_pattern = {R"(([0-9A-Z ])([0-9A-Z])([0-9])([A-Z ])([A-Z ])([A-Z ]))"};
@@ -44,21 +44,31 @@ QMap<QString, int> directed_cmds = {
{"@", 1 }, // query qth
{"&", 2 }, // query station message
{"$", 3 }, // query station(s) heard
{"%", 5 }, // query pwr
// 4.
{"^", 4 }, // query grid
// {"%" 5 }, // unused
{"|", 6 }, // retransmit message
{"!", 7 }, // alert message
{"#", 8 }, // all or nothing message
// {"=", 9 }, // unused? (can we even use equals?)
// {"/", 10 }, // unused? (can we even use stroke?)
// {"=", 9 }, // unused
// {"/", 10 }, // unused
// {"/", 11 }, // unused
// {"/", 12 }, // unused
// {"/", 13 }, // unused
// directed responses
{" QSO", 13 }, // can you communicate with? i can communicate with
{" APRS:", 14 }, // send an aprs packet
{" GRID", 15 }, // this is my current grid locator
{" QTC", 16 }, // this is my qtc message
{" QTH", 17 }, // this is my qth message
{" FB", 18 }, // fine business
{" HW CPY?", 19 }, // how do you copy?
{" HEARING", 20 }, // i am hearing the following stations
{" RR", 21 }, // roger roger (not visible in UI but still exists)
{" RR", 21 }, // roger roger
{" QSL?", 22 }, // do you copy?
{" QSL", 23 }, // i copy
{" PWR", 24 }, // power level
// {"", 24 }, // unused
{" SNR", 25 }, // seen a station at the provided snr
{" NO", 26 }, // negative confirm
{" YES", 27 }, // confirm
@@ -68,21 +78,28 @@ QMap<QString, int> directed_cmds = {
{" ", 31 }, // send freetext
};
QSet<int> allowed_cmds = {0, 1, 2, 3, /*4,*/ 5, 6, 7, 8, /*...*/ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
QSet<int> allowed_cmds = {0, 1, 2, 3, 4, /*5,*/ 6, 7, 8, /*...*/ 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, /*24,*/ 25, 26, 27, 28, 29, 30, 31};
QSet<int> buffered_cmds = {6, 7, 8};
QSet<int> buffered_cmds = {6, 7, 8, 13, 14, 15};
QMap<int, int> checksum_cmds = {
{ 6, 16 },
{ 7, 16 },
{ 8, 32 },
{ 13, 16 },
{ 14, 16 },
{ 15, 0 }
};
QString callsign_pattern = QString("(?<callsign>[A-Z0-9/]+)");
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|ACK|73|YES|NO|SNR|PWR|QSL[?]?|RR|HEARING|[?@&$%|!# ]))?");
QString optional_cmd_pattern = QString("(?<cmd>\\s?(?:AGN[?]|ACK|73|YES|NO|SNR|QSL[?]?|RR|HEARING|HW CPY[?]|FB|QTH|QTC|GRID|APRS[:]|QSO|[?@&$%|!#^ ]))?");
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_pwr_pattern = QString("(?<pwr>(?<=PWR)\\s?\\d+\\s?[KM]?W)?");
QString optional_num_pattern = QString("(?<num>(?<=SNR|HEARING)\\s?[-+]?(?:3[01]|[0-2]?[0-9]))?");
QRegularExpression directed_re("^" +
callsign_pattern +
optional_cmd_pattern +
optional_pwr_pattern +
optional_num_pattern);
QRegularExpression beacon_re(R"(^\s*(?<type>CQCQCQ|BEACON)(?:\s(?<grid>[A-R]{2}[0-9]{2}))?\b)");
@@ -92,7 +109,6 @@ QRegularExpression compound_re("^\\s*[<]" +
"(?<extra>" +
optional_grid_pattern +
optional_cmd_pattern +
optional_pwr_pattern +
optional_num_pattern +
")[>]");
@@ -421,19 +437,6 @@ QString Varicode::formatSNR(int snr){
return QString("%1%2").arg(snr >= 0 ? "+" : "").arg(snr, snr < 0 ? 3 : 2, 10, QChar('0'));
}
QString Varicode::formatPWR(int dbm){
if(dbm < 0 || dbm > 60){
return QString();
}
int mwatts = dbmTomwatts(dbm);
if(mwatts < 1000){
return QString("%1mW").arg(mwatts);
}
return QString("%1W").arg(mwatts/1000);
}
QString Varicode::checksum16(QString const &input){
auto fromBytes = input.toLocal8Bit();
auto crc = CRC::Calculate(fromBytes.data(), fromBytes.length(), CRC::CRC_16_KERMIT());
@@ -947,7 +950,7 @@ QString Varicode::unpackCallsign(quint32 value){
return callsign;
}
QString deg2grid(float dlong, float dlat){
QString Varicode::deg2grid(float dlong, float dlat){
QChar grid[6];
if(dlong < -180){
@@ -980,7 +983,7 @@ QString deg2grid(float dlong, float dlat){
return QString(grid, 6);
}
QPair<float, float> grid2deg(QString const &grid){
QPair<float, float> Varicode::grid2deg(QString const &grid){
QPair<float, float> longLat;
QString g = grid;
@@ -1012,7 +1015,7 @@ quint16 Varicode::packGrid(QString const& value){
return (1<<15)-1;
}
auto pair = grid2deg(grid.left(4));
auto pair = Varicode::grid2deg(grid.left(4));
int ilong = pair.first;
int ilat = pair.second + 90;
@@ -1027,7 +1030,7 @@ QString Varicode::unpackGrid(quint16 value){
float dlat = value % 180 - 90;
float dlong = value / 180 * 2 - 180 + 2;
return deg2grid(dlong, dlat).left(4);
return Varicode::deg2grid(dlong, dlat).left(4);
}
// pack a number or snr into an integer between 0 & 62
@@ -1042,43 +1045,18 @@ quint8 Varicode::packNum(QString const &num, bool *ok){
return inum + 30 + 1;
}
// pack pwr string into a dbm between 0 and 62
quint8 Varicode::packPwr(QString const &pwr, bool *ok){
int ipwr = 0;
if(pwr.isEmpty()){
if(ok) *ok = false;
return ipwr;
}
int factor = 1000;
if(pwr.endsWith("KW")){
factor = 1000000;
}
else if(pwr.endsWith("MW")){
factor = 1;
}
ipwr = QString(pwr).replace(QRegExp("[KM]?W", Qt::CaseInsensitive), "").toInt() * factor;
ipwr = mwattsToDbm(ipwr);
if(ok) *ok = true;
return ipwr + 1;
}
// pack a reduced fidelity command and a number into the extra bits provided between nbasegrid and nmaxgrid
quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
//quint8 allowed = nmaxgrid - nbasegrid - 1;
// if cmd == pwr || cmd == snr
// if cmd == snr
quint8 value = 0;
if(cmd == directed_cmds[" PWR"] || cmd == directed_cmds[" SNR"]){
if(cmd == directed_cmds[" SNR"]){
// 8 bits - 1 bit flag + 1 bit type + 6 bit number
// [1][X][6]
// X = 0 == SNR
// X = 1 == PWR
value = ((1 << 1) + ((int)cmd == directed_cmds[" PWR"])) << 6;
value = value + num;
value = (1 << 1) << 6;
value = value + (num & ((1<<6)-1));
if(pPackedNum) *pPackedNum = true;
} else {
value = cmd & ((1<<7)-1);
@@ -1089,18 +1067,10 @@ quint8 Varicode::packCmd(quint8 cmd, quint8 num, bool *pPackedNum){
}
quint8 Varicode::unpackCmd(quint8 value, quint8 *pNum){
// if the first bit is 1, the second bit will indicate if its pwr or snr...
// if the first bit is 1, this is an SNR with a number encoded in the lower 6 bits
if(value & (1<<7)){
// either pwr or snr...
bool pwr = value & (1<<6);
if(pNum) *pNum = value & ((1<<6)-1);
if(pwr){
return directed_cmds[" PWR"];
} else {
return directed_cmds[" SNR"];
}
return directed_cmds[" SNR"];
} else {
if(pNum) *pNum = 0;
return value & ((1<<7)-1);
@@ -1115,6 +1085,14 @@ bool Varicode::isCommandBuffered(const QString &cmd){
return directed_cmds.contains(cmd) && buffered_cmds.contains(directed_cmds[cmd]);
}
int Varicode::isCommandChecksumed(const QString &cmd){
if(!directed_cmds.contains(cmd) || !checksum_cmds.contains(directed_cmds[cmd])){
return 0;
}
return checksum_cmds[directed_cmds[cmd]];
}
// CQCQCQ EM73
// BEACON EM73
QString Varicode::packBeaconMessage(QString const &text, const QString &callsign, int *n){
@@ -1211,7 +1189,6 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
QString grid = parsedText.captured("grid");
QString cmd = parsedText.captured("cmd");
QString num = parsedText.captured("num").trimmed();
QString pwr = parsedText.captured("pwr").trimmed().toUpper();
QString base;
QString fix;
@@ -1245,9 +1222,6 @@ QString Varicode::packCompoundMessage(QString const &text, int *n){
if (!cmd.isEmpty() && directed_cmds.contains(cmd) && Varicode::isCommandAllowed(cmd)){
bool packedNum = false;
qint8 inum = Varicode::packNum(num, nullptr);
if(cmd == " PWR"){
inum = Varicode::packPwr(pwr, nullptr);
}
extra = nusergrid + Varicode::packCmd(directed_cmds[cmd], inum, &packedNum);
type = FrameCompoundDirected;
@@ -1278,9 +1252,7 @@ QStringList Varicode::unpackCompoundMessage(const QString &text, quint8 *pType){
unpacked.append(directed_cmds.key(cmd));
if(cmd == directed_cmds[" PWR"]){
unpacked.append(Varicode::formatPWR(num - 1));
} else if(cmd == directed_cmds[" SNR"]){
if(cmd == directed_cmds[" SNR"]){
unpacked.append(Varicode::formatSNR(num - 31));
}
}
@@ -1385,7 +1357,6 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
QString to = match.captured("callsign");
QString cmd = match.captured("cmd");
QString num = match.captured("num").trimmed();
QString pwr = match.captured("pwr").trimmed().toUpper();
// ensure we have a directed command
if(cmd.isEmpty()){
@@ -1412,23 +1383,15 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
}
}
// validate command
if(!Varicode::isCommandAllowed(cmd)){
if(!Varicode::isCommandAllowed(cmd) && !Varicode::isCommandAllowed(cmd.trimmed())){
if(n) *n = 0;
return frame;
}
// packing general number...
quint8 inum = 0;
if(cmd.trimmed() == "PWR"){
inum = Varicode::packPwr(pwr, nullptr);
if(pNum) *pNum = pwr;
} else {
inum = Varicode::packNum(num, nullptr);
if(pNum) *pNum = num;
}
quint8 inum = Varicode::packNum(num, nullptr);
if(pNum) *pNum = num;
quint32 packed_from = Varicode::packCallsign(from);
quint32 packed_to = Varicode::packCallsign(to);
@@ -1438,7 +1401,13 @@ QString Varicode::packDirectedMessage(const QString &text, const QString &callsi
return frame;
}
quint8 packed_cmd = directed_cmds[cmd];
quint8 packed_cmd = 0;
if(directed_cmds.contains(cmd)){
packed_cmd = directed_cmds[cmd];
}
if(directed_cmds.contains(cmd.trimmed())){
packed_cmd = directed_cmds[cmd.trimmed()];
}
quint8 packed_flag = FrameDirected;
quint8 packed_extra = inum;
@@ -1485,9 +1454,7 @@ QStringList Varicode::unpackDirectedMessage(const QString &text, quint8 *pType){
if(extra != 0){
// TODO: jsherer - should we decide which format to use on the command, or something else?
if(packed_cmd == directed_cmds[" PWR"]){
unpacked.append(Varicode::formatPWR(extra-1));
} else if(packed_cmd == directed_cmds[" SNR"]) {
if(packed_cmd == directed_cmds[" SNR"]) {
unpacked.append(Varicode::formatSNR((int)extra-31));
} else {
unpacked.append(QString("%1").arg(extra-31));
+6 -3
View File
@@ -41,11 +41,11 @@ public:
"FrameBeacon",
"FrameCompound",
"FrameCompoundDirected",
"FrameDirectedPositive",
"FrameDirectedNegative",
"FrameDirected",
"FrameReservedA",
"FrameDataUnpadded",
"FrameDataPadded",
"FrameReserved"
"FrameReservedB"
};
if(type > FrameTypeMax){
@@ -109,6 +109,8 @@ public:
static quint32 packCallsign(QString const& value);
static QString unpackCallsign(quint32 value);
static QString deg2grid(float dlong, float dlat);
static QPair<float, float> grid2deg(QString const &grid);
static quint16 packGrid(QString const& value);
static QString unpackGrid(quint16 value);
@@ -119,6 +121,7 @@ public:
static bool isCommandAllowed(const QString &cmd);
static bool isCommandBuffered(const QString &cmd);
static int isCommandChecksumed(const QString &cmd);
static QString packBeaconMessage(QString const &text, QString const&callsign, int *n);
static QStringList unpackBeaconMessage(const QString &text, quint8 *pType, bool *isAlt);
+5 -3
View File
@@ -80,14 +80,14 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
ui->widePlot->setBinsPerPixel(nbpp);
ui->sbPercent2dPlot->setValue(m_Percent2DScreen);
ui->widePlot->SetPercent2DScreen(m_Percent2DScreen);
ui->widePlot->setStartFreq(m_settings->value("StartFreq",0).toInt());
ui->widePlot->setStartFreq(m_settings->value("StartFreq", 500).toInt());
ui->fStartSpinBox->setValue(ui->widePlot->startFreq());
m_waterfallPalette=m_settings->value("WaterfallPalette","Default").toString();
m_userPalette = WFPalette {m_settings->value("UserPalette").value<WFPalette::Colours> ()};
m_fMinPerBand = m_settings->value ("FminPerBand").toHash ();
setRxRange ();
ui->controls_widget->setVisible(!m_settings->value("HideControls", true).toBool());
ui->cbControls->setChecked(!m_settings->value("HideControls", true).toBool());
ui->controls_widget->setVisible(!m_settings->value("HideControls", false).toBool());
ui->cbControls->setChecked(!m_settings->value("HideControls", false).toBool());
}
int index=0;
@@ -212,6 +212,8 @@ void WideGraph::on_offsetSpinBox_valueChanged(int n){
return;
}
n = qMax(500, n);
setRxFreq(n);
setTxFreq(n);
setFreq2(n, n);
+3
View File
@@ -177,6 +177,9 @@
<property name="singleStep">
<number>100</number>
</property>
<property name="value">
<number>500</number>
</property>
</widget>
</item>
<item row="1" column="12">
+6 -2
View File
@@ -70,7 +70,9 @@ SOURCES += \
EqualizationToolsDialog.cpp \
varicode.cpp \
NetworkMessage.cpp \
MessageClient.cpp
MessageClient.cpp \
SelfDestructMessageBox.cpp \
APRSISClient.cpp
HEADERS += qt_helpers.hpp \
pimpl_h.hpp pimpl_impl.hpp \
@@ -92,7 +94,9 @@ HEADERS += qt_helpers.hpp \
qpriorityqueue.h \
crc.h \
NetworkMessage.hpp \
MessageClient.hpp
MessageClient.hpp \
SelfDestructMessageBox.h \
APRSISClient.h
INCLUDEPATH += qmake_only