JS8Call-Improved master
Loading...
Searching...
No Matches
mainwindow.h
1// -*- Mode: C++ -*-
2#ifndef MAINWINDOW_H
3#define MAINWINDOW_H
4
5#include "JS8_Audio/AudioDevice.h"
6#include "JS8_Audio/NotificationAudio.h"
7#include "JS8_Audio/SoundInput.h"
8#include "JS8_Audio/SoundOutput.h"
9#include "JS8_Include/EventFilter.h"
10#include "JS8_Include/commons.h"
11#include "JS8_Include/qpriorityqueue.h"
12#include "JS8_JSC/JSC_checker.h"
13#include "JS8_Logbook/LogBook.h"
16#include "JS8_Main/Bands.h"
17#include "JS8_Main/DirectedMessageHighlighter.h"
18#include "JS8_Main/DriftingDateTime.h"
19#include "JS8_Main/FrequencyList.h"
20#include "JS8_Main/Geodesic.h"
21#include "JS8_Main/HBBlockingDB.h"
22#include "JS8_Main/HelpTextWindow.h"
23#include "JS8_Main/Inbox.h"
24#include "JS8_Main/JS8MessageBox.h"
25#include "JS8_Main/MessageClient.h"
26#include "JS8_Main/MessageServer.h"
27#include "JS8_Main/Modes.h"
28#include "JS8_Main/MultiSettings.h"
30#include "JS8_Main/ProcessThread.h"
31#include "JS8_Main/Radio.h"
32#include "JS8_Main/SelfDestructMessageBox.h"
33#include "JS8_Main/SignalMeter.h"
34#include "JS8_Main/StationList.h"
35#include "JS8_Main/TxLoop.h"
36#include "JS8_Main/Varicode.h"
37#include "JS8_Main/qt_helpers.h"
38#include "JS8_Main/revision_utils.h"
39#include "JS8_Mode/DecodedText.h"
40#include "JS8_Mode/Decoder.h"
41#include "JS8_Mode/Detector.h"
42#include "JS8_Mode/JS8.h"
43#include "JS8_Mode/JS8Submode.h"
44#include "JS8_Mode/Modulator.h"
45#include "JS8_Network/NetworkAccessManager.h"
46#include "JS8_Network/PSKReporter.h"
47#include "JS8_Network/SpotClient.h"
48#include "JS8_Network/TCPClient.h"
49#include "JS8_Transceiver/Transceiver.h"
50#include "JS8_Transceiver/TransceiverFactory.h"
51#include "JS8_UDP/WSJTXMessageClient.h"
52#include "JS8_UDP/WSJTXMessageMapper.h"
53#include "JS8_UI/About.h"
54#include "JS8_UI/Configuration.h"
55#include "JS8_UI/WideGraph.h"
56#include "JS8_UI/MessagePanel.h"
57#include "LogQSO.h"
58#include "MessageReplyDialog.h"
59#include "styles.h"
60#include "ui_mainwindow.h"
61
62#include <QAbstractSocket>
63#include <QAction>
64#include <QActionGroup>
65#include <QApplication>
66#include <QAudioDevice>
67#include <QByteArrayView>
68#include <QCursor>
69#include <QDateTime>
70#include <QDesktopServices>
71#include <QDir>
72#include <QDockWidget>
73#include <QElapsedTimer>
74#include <QFileDialog>
75#include <QHash>
76#include <QHostAddress>
77#include <QHostInfo>
78#include <QInputDialog>
79#include <QLabel>
80#include <QLineEdit>
81#include <QList>
82#include <QLoggingCategory>
83#include <QMainWindow>
84#include <QMdiSubWindow>
85#include <QMutex>
86#include <QMutexLocker>
87#include <QNetworkAccessManager>
88#include <QNetworkReply>
89#include <QNetworkRequest>
90#include <QPair>
91#include <QPixmap>
92#include <QPointer>
93#include <QProgressBar>
94#include <QProgressDialog>
95#include <QRegularExpression>
96#include <QRegularExpressionValidator>
97#include <QScopedPointer>
98#include <QScrollBar>
99#include <QSet>
100#include <QSoundEffect>
101#include <QStandardPaths>
102#include <QStringBuilder>
103#include <QStyleFactory>
104#include <QtCore/QtGlobal>
105#include <QTableWidget>
106#include <QTextEdit>
107#include <QThread>
108#include <QTime>
109#include <QTimeZone>
110#include <QTimer>
111#include <QToolTip>
112#include <QUdpSocket>
113#include <QUrl>
114#include <QVariant>
115#include <QVector>
116#include <QVersionNumber>
117#include <QtConcurrent/QtConcurrentRun>
118#include <QtGui>
119#include <boost/crc.hpp>
120#include <fftw3.h>
121
122#include <algorithm>
123#include <array>
124#include <cmath>
125#include <complex>
126#include <cstring>
127#include <functional>
128#include <iterator>
129#include <mutex>
130#include <stdexcept>
131#include <string_view>
132#include <unordered_map>
133#include <vector>
134
135#if QT_VERSION < QT_VERSION_CHECK(6, 9, 3)
136#error "Qt >= 6.9.3 is required to build JS8Call. Please upgrade your Qt toolchain."
137#endif
138
139Q_DECLARE_LOGGING_CATEGORY(mainwindow_js8)
140
141extern int volatile itone[JS8_NUM_SYMBOLS]; // Audio tones for all Tx symbols
142
143//--------------------------------------------------------------- mainwindow
144// How often to poll the UI, in MS.
145// Some things may depend on this being a divisor of 1000.
146constexpr quint32 UI_POLL_INTERVAL_MS = 100;
147
148namespace {
149namespace Default {
150constexpr Radio::Frequency DIAL_FREQUENCY = 14078000;
151constexpr auto FREQUENCY = 1500;
152constexpr auto SUBMODE = Varicode::JS8CallNormal;
153} // namespace Default
154
155namespace State {
156constexpr auto RX = 1;
157constexpr auto TX = 2;
158} // namespace State
159} // namespace
160
161namespace Ui {
162class UI_Constructor;
163}
164
165class QSettings;
166class QLineEdit;
167class QFont;
168class QHostInfo;
169class WideGraph;
170class LogQSO;
171class Transceiver;
172class MessageClient;
173class QTime;
174class HelpTextWindow;
175class SoundOutput;
176class Modulator;
177class SoundInput;
178class Detector;
179class AprsInboundRelay;
180class MultiSettings;
181class DecodedText;
182class JSCChecker;
183class MessagePanel;
184
185using namespace std;
186typedef std::function<void()> Callback;
187
188class WSJTXMessageMapper; // Forward declaration
189
190class UI_Constructor : public QMainWindow {
191 Q_OBJECT;
192 friend class WSJTXMessageMapper; // Allow WSJTXMessageMapper to access
193 // private members
194
195 struct CallDetail;
196 struct CommandDetail;
197
198 public:
199 using Frequency = Radio::Frequency;
200 using FrequencyDelta = Radio::FrequencyDelta;
201 using Mode = Modes::Mode;
202
203 explicit UI_Constructor(QString const &program_info,
204 QDir const &temp_directory, bool multiple,
205 MultiSettings *settings, QWidget *parent = nullptr);
207
208 private:
209 struct SortByReverse {
210 QString by;
211 bool reverse;
212 };
213
224 bool m_stopTxButtonIsLongterm;
225 bool m_hbButtonIsLongterm;
226 bool m_cqButtonIsLongterm;
227
228 public slots:
229 void showSoundInError(const QString &errorMsg);
230 void showSoundOutError(const QString &errorMsg);
231 void showStatusMessage(const QString &statusMsg);
232 void dataSink(qint64 frames); // JS8_Mainwindow/dataSink.cpp
238 void guiUpdate();
239 void setXIT(int n);
240 void qsy(int hzDelta);
241 void onDriftChanged(qint64 new_drift_ms);
242 bool tryRestoreFreqOffset();
243 void changeFreq(int);
244
245 bool hasExistingMessageBufferToMe(int *pOffset);
246 bool hasExistingMessageBuffer(int submode, int offset, bool drift,
247 int *pPrevOffset);
248 bool hasClosedExistingMessageBuffer(int offset);
249 void logCallActivity(CallDetail d, bool spot = true);
250 void logHeardGraph(QString from, QString to);
251 QString lookupCallInCompoundCache(QString const &call);
252 void cacheActivity(QString key);
253 void restoreActivity(QString key);
254 void clearActivity();
255 void clearBandActivity();
256 void clearRXActivity();
257 void clearCallActivity();
258 void createGroupCallsignTableRows(QTableWidget *table,
259 const QString &selectedCall,
260 bool &showIconColumn);
261 void displayTextForFreq(QString text, int freq, QDateTime date, bool isTx,
262 bool isNewLine, bool isLast);
263 void writeNoticeTextToUI(QDateTime date, QString text);
264 int writeMessageTextToUI(QDateTime date, QString text, int freq, bool isTx,
265 int block = -1);
266 bool isMessageQueuedForTransmit();
267 bool isInDecodeDelayThreshold(int seconds);
268 void prependMessageText(QString text);
269 void addMessageText(QString text, bool clear = false,
270 bool selectFirstPlaceholder = false);
271 void confirmThenEnqueueMessage(int timeout, int priority, QString message,
272 int offset, Callback c); // JS8_Mainwindow/confirmThenEnqueueMessage.cpp
273 void enqueueMessage(int priority, QString message, int offset, Callback c);
274 void resetMessage();
275 void resetMessageUI();
276 void restoreMessage();
277 void initializeDummyData(); // JS8_Mainwindow/initializeDummyData.cpp
278 void initializeGroupMessage(); // JS8_Mainwindow/initializeGroupMessage.cpp
279 bool ensureCallsignSet(bool alert = true);
280 bool ensureKeyNotStuck(QString const &text);
281 bool ensureNotIdle();
282 bool ensureCanTransmit();
283 bool ensureCreateMessageReady(const QString &text);
284 QString createMessage(QString const &text, bool *pDisableTypeahead);
285 QString appendMessage(QString const &text, bool isData,
286 bool *pDisableTypeahead);
287 QString createMessageTransmitQueue(QString const &text, bool reset,
288 bool isData, bool *pDisableTypeahead);
290 QPair<QString, int> popMessageFrame();
291 void tryNotify(const QString &key);
292 void processDecodeEvent(JS8::Event::Variant const &); // JS8_Mainwindow/processDecodeEvent.cpp
293
294 void updateCQButtonDisplay();
295 void updateHBButtonDisplay();
296
297 protected:
298 void keyPressEvent(QKeyEvent *) override;
299 void closeEvent(QCloseEvent *) override;
300 void childEvent(QChildEvent *) override;
301 bool eventFilter(QObject *, QEvent *) override;
302
303 private slots:
304 void initialize_fonts();
305 void on_menuModeJS8_aboutToShow();
306 void on_menuControl_aboutToShow();
307 void on_actionCheck_for_Updates_triggered();
308 void on_actionEnable_Monitor_RX_toggled(bool checked);
309 void on_actionEnable_Transmitter_TX_toggled(bool checked);
310 void on_actionEnable_Reporting_SPOT_toggled(bool checked);
311 void on_actionEnable_Tuning_Tone_TUNE_toggled(bool checked);
312 void on_menuWindow_aboutToShow();
313 void on_actionFocus_Message_Receive_Area_triggered();
314 void on_actionFocus_Message_Reply_Area_triggered();
315 void on_actionFocus_Band_Activity_Table_triggered();
316 void on_actionFocus_Call_Activity_Table_triggered();
317 void on_actionClear_All_Activity_triggered();
318 void on_actionClear_Band_Activity_triggered();
319 void on_actionClear_RX_Activity_triggered();
320 void on_actionClear_Call_Activity_triggered();
321 void on_actionSetOffset_triggered();
322 void on_actionShow_Fullscreen_triggered(bool checked);
323 void on_actionShow_Statusbar_triggered(bool checked);
324 void on_actionShow_Frequency_Clock_triggered(bool checked);
325 void on_actionShow_Band_Activity_triggered(bool checked);
326 void on_actionShow_Band_Heartbeats_and_ACKs_triggered(bool checked);
327 void on_actionShow_Call_Activity_triggered(bool checked);
328 void on_actionShow_Waterfall_triggered(bool checked);
329 void on_actionShow_Waterfall_Controls_triggered(bool checked);
330 void on_actionShow_Waterfall_Time_Drift_Controls_triggered(bool checked);
331 void on_actionReset_Window_Sizes_triggered();
332 void on_actionSettings_triggered();
333 void openSettings(int tab = 0);
334 void prepareApi();
335 void prepareSpotting();
336 void on_spotButton_clicked(bool checked);
337 void on_monitorButton_clicked(bool);
338 void on_actionAbout_triggered();
339 void resetPushButtonToggleText(QPushButton *btn);
340 void on_stopTxButton_clicked();
341 void on_dialFreqUpButton_clicked();
342 void on_dialFreqDownButton_clicked();
343 void on_actionAdd_Log_Entry_triggered();
344 void on_actionOpen_log_directory_triggered();
345 void on_actionCopyright_Notice_triggered();
346 void on_actionUser_Guide_triggered();
347 bool decode(qint32 k);
348 bool isDecodeReady(int submode, qint32 k, qint32 k0,
349 qint32 *pCurrentDecodeStart, qint32 *pNextDecodeStart,
350 qint32 *pStart, qint32 *pSz, qint32 *pCycle);
351 bool decodeEnqueueReady(qint32 k, qint32 k0);
352 bool decodeEnqueueReadyExperiment(qint32 k, qint32 k0);
353 bool decodeProcessQueue(qint32 *pSubmode);
354 void decodeStart();
355 void decodeBusy(bool b);
356 void decodeDone();
357 void on_startTxButton_toggled(bool checked);
358 void toggleTx(bool start);
359 void on_logQSOButton_clicked();
360 void on_actionModeJS8HB_toggled(bool checked);
361 void on_actionModeJS8Normal_triggered();
362 void on_actionModeJS8Fast_triggered();
363 void on_actionModeJS8Turbo_triggered();
364 void on_actionModeJS8Slow_triggered();
365 void on_actionModeJS8Ultra_triggered();
366 void on_actionHeartbeatAcknowledgements_toggled(bool checked);
367 void on_actionModeMultiDecoder_toggled(bool checked);
368 void on_actionModeAutoreply_toggled(bool checked);
369 bool canCurrentModeSendHeartbeat() const;
370 void prepareMonitorControls();
371 void prepareHeartbeatMode(bool enabled);
372 void f11f12(int n);
373 void on_actionErase_ALL_TXT_triggered();
374 void on_actionErase_js8call_log_adi_triggered();
375 void startTx();
376 void stopTx();
377 void stopTx2();
378 void buildFrequencyMenu(QMenu *menu);
379 void buildHeartbeatMenu(QMenu *menu);
380 void buildCQMenu(QMenu *menu);
381 void buildRepeatMenu(QMenu *menu, QPushButton *button, bool isLowInterval,
382 int *interval);
383 void sendHB();
384 void sendHeartbeatAck(QString to, int snr, QString extra);
385 void on_hbMacroButton_toggled(bool checked);
386 void on_hbMacroButton_clicked();
387 void sendCQ(bool repeat = false);
388 void on_cqMacroButton_toggled(bool checked);
389 void on_cqMacroButton_clicked();
390 void on_replyMacroButton_clicked();
391 void on_snrMacroButton_clicked();
392 void on_infoMacroButton_clicked();
393 void on_statusMacroButton_clicked();
394 void setShowColumn(QString tableKey, QString columnKey, bool value);
395 bool showColumn(QString tableKey, QString columnKey, bool default_ = true);
396 void buildShowColumnsMenu(QMenu *menu, QString tableKey);
397 void setSortBy(QString key, QString value);
398 QString getSortBy(QString const &key, QString const &defaultValue) const;
399 SortByReverse getSortByReverse(QString const &key,
400 QString const &defaultValue) const;
401 void buildSortByMenu(QMenu *menu, QString key, QString defaultValue,
402 QList<QPair<QString, QString>> values);
403 void buildBandActivitySortByMenu(QMenu *menu);
404 void buildCallActivitySortByMenu(QMenu *menu);
405 void buildQueryMenu(QMenu *, QString callsign); // JS8_Mainwindow/buildQueryMenu.cpp
406 QMap<QString, QString> buildMacroValues();
407 void buildColumnLabelMap();
408 void buildSuggestionsMenu(QMenu *menu, QTextEdit *edit,
409 const QPoint &point);
410 void buildSavedMessagesMenu(QMenu *menu);
411 void buildRelayMenu(QMenu *menu);
412 QAction *buildRelayAction(QString call);
413 void buildEditMenu(QMenu *, QTextEdit *);
414 void on_queryButton_pressed();
415 void on_macrosMacroButton_pressed();
416 void on_deselectButton_pressed();
417 void on_tableWidgetRXAll_cellClicked(int row, int col);
418 void on_tableWidgetRXAll_cellDoubleClicked(int row, int col);
419 QString generateCallDetail(QString selectedCall);
420 void on_tableWidgetCalls_cellClicked(int row, int col);
421 void on_tableWidgetCalls_cellDoubleClicked(int row, int col);
422 QList<QPair<QString, int>> buildMessageFrames(QString const &text,
423 bool isData,
424 bool *pDisableTypeahead);
425 bool prepareNextMessageFrame();
426 bool isFreqOffsetFree(int f, int bw);
427 int findFreeFreqOffset(int fmin, int fmax, int bw);
428 void setDrift(int n);
429 void on_tuneButton_clicked(bool);
430 void acceptQSO(QDateTime const &, QString const &call, QString const &grid,
431 Frequency dial_freq, QString const &mode,
432 QString const &submode, QString const &rpt_sent,
433 QString const &rpt_received, QString const &comments,
434 QString const &name, QDateTime const &QSO_date_on,
435 QString const &operator_call, QString const &my_call,
436 QString const &my_grid, QByteArray const &ADIF,
437 QVariantMap const &additionalFields);
438 void on_readFreq_clicked();
439 void on_outAttenuation_valueChanged(int);
440 void rigOpen();
441 void handle_transceiver_update(Transceiver::TransceiverState const &);
442 void handle_transceiver_failure(QString const &reason);
443 void band_changed();
444 void monitor(bool);
445 void end_tuning();
446 void stop_tuning();
447 void stopTuneATU();
448 void auto_tx_mode(bool);
449 void on_monitorButton_toggled(bool checked);
450 void on_monitorTxButton_toggled(bool checked);
451 void on_tuneButton_toggled(bool checked);
452 void on_spotButton_toggled(bool checked);
453
454 void emitPTT(bool on);
455 void emitTones();
456 void udpNetworkMessage(Message const &message);
457 void tcpNetworkMessage(Message const &message);
458 void networkMessage(Message const &message); // JS8_Mainwindow/networkMessage.cpp
459 bool canSendNetworkMessage();
460 void sendNetworkMessage(QString const &type, QString const &message);
461 void sendNetworkMessage(QString const &type, QString const &message,
462 const QVariantMap &params);
463 void pskReporterError(QString const &);
464 void TxAgain();
465 void checkVersion(bool alertOnUpToDate); // JS8_Mainwindow/checkVersion.cpp
466 void checkStartupWarnings();
467 void clearCallsignSelected();
468 void refreshTextDisplay();
469
470 void manualBandHop(const StationList::Station station);
471
472 private:
473 Q_SIGNAL void apiSetMaxConnections(int n);
474 Q_SIGNAL void apiSetServer(QString host, quint16 port);
475 Q_SIGNAL void apiStartServer();
476 Q_SIGNAL void apiStopServer();
477
478 Q_SIGNAL void aprsClientEnqueueSpot(QString by_call, QString from_call,
479 QString grid, QString comment);
480 Q_SIGNAL void aprsClientEnqueueThirdParty(QString by_call,
481 QString from_call, QString text);
488 Q_SIGNAL void aprsClientEnqueueAck(QString from_call, QString to_call,
489 QString messageId);
490 Q_SIGNAL void aprsClientSetSkipPercent(float skipPercent);
491 Q_SIGNAL void aprsClientSetIncomingRelayEnabled(bool enabled);
492 Q_SIGNAL void aprsClientSetServer(QString host, quint16 port);
493 Q_SIGNAL void aprsClientSetPaused(bool paused);
494 Q_SIGNAL void aprsClientSetLocalStation(QString mycall, QString passcode);
495 Q_SIGNAL void aprsClientSendReports();
496
497 Q_SIGNAL void pskReporterSendReport(bool);
498 Q_SIGNAL void pskReporterSetLocalStation(QString, QString, QString);
499 Q_SIGNAL void pskReporterAddRemoteStation(QString, QString,
500 Radio::Frequency, QString, int,
501 QDateTime);
502
503 Q_SIGNAL void spotClientSetLocalStation(QString, QString, QString);
504 Q_SIGNAL void spotClientEnqueueCmd(QString, QString, QString, QString,
505 QString, QString, QString, int, int, int,
506 int);
507 Q_SIGNAL void spotClientEnqueueSpot(QString, QString, int, int, int, int);
508
509 Q_SIGNAL void decodedLineReady(QByteArray t);
510 Q_SIGNAL void playNotification(const QString &name);
511 Q_SIGNAL void initializeNotificationAudioOutputStream(const QAudioDevice &,
512 unsigned) const;
513 Q_SIGNAL void initializeAudioOutputStream(QAudioDevice, unsigned channels,
514 unsigned msBuffered) const;
515 Q_SIGNAL void stopAudioOutputStream() const;
516 Q_SIGNAL void startAudioInputStream(QAudioDevice const &,
517 int framesPerBuffer, AudioDevice *sink,
518 AudioDevice::Channel) const;
519 Q_SIGNAL void suspendAudioInputStream() const;
520 Q_SIGNAL void resumeAudioInputStream() const;
521 Q_SIGNAL void startDetector(AudioDevice::Channel) const;
522 Q_SIGNAL void FFTSize(unsigned) const;
523 Q_SIGNAL void detectorClose() const;
524 Q_SIGNAL void finished() const;
525 Q_SIGNAL void transmitFrequency(double) const;
526 Q_SIGNAL void endTransmitMessage(bool quick = false) const;
527 Q_SIGNAL void tune(bool = true) const;
528 Q_SIGNAL void sendMessage(double frequency, int submode, double txDelay,
529 SoundOutput *, AudioDevice::Channel) const;
530 Q_SIGNAL void outAttenuationChanged(qreal) const;
531 Q_SIGNAL void toggleShorthand() const;
532 Q_SIGNAL void submodeChanged(Varicode::SubmodeType) const;
533
534 Q_SIGNAL void messageAdded(int) const;
535
536 private:
537 QByteArray wisdomFileName() const;
538
539 void writeAllTxt(QStringView message);
540 void writeMsgTxt(QStringView message, int snr, int offset);
541
542 void currentTextChanged();
543 void tableSelectionChanged(QItemSelection const &, QItemSelection const &);
544 void setupJS8();
545 void applyPillSettings();
546
547 int freq() const { return m_freq; }
548
550 void refuseToSendIn30mWSPRBand();
551
552 void prepareSending(qint64 nowMS);
553
555 void updateClockUI(const QDateTime &);
556
557 void setFreq(int);
558 void transmit();
559
560 bool presentlyWantHBReplies();
561
562 QString m_nextFreeTextMsg;
563
564 NetworkAccessManager m_network_manager;
565 bool m_valid;
566 [[maybe_unused]] bool m_multiple; // Used only in Windows builds
567 MultiSettings *m_multi_settings;
568 QPushButton *m_configurations_button;
569 QSettings *m_settings;
570 bool m_settings_read;
571 QScopedPointer<Ui::UI_Constructor> ui;
572
573 // other windows
574 Configuration m_config;
575 JS8MessageBox m_rigErrorMessageBox;
576
577 QDockWidget* messageDock_ = nullptr;
578 MessagePanel* messagePanel_ = nullptr;
579 QDialog* messageFloatDialog_ = nullptr;
580
581 enum class MessageHost { Dock, Dialog };
582 MessageHost messageHost_ = MessageHost::Dock;
583
584 QScopedPointer<WideGraph> m_wideGraph;
585 QScopedPointer<LogQSO> m_logDlg;
586 QScopedPointer<HelpTextWindow> m_shortcuts;
587 QScopedPointer<HelpTextWindow> m_prefixes;
588 QScopedPointer<HelpTextWindow> m_mouseCmnds;
589
591 Frequency m_lastDialFreq;
592 QString m_lastBand;
593
594 Detector *m_detector;
595 unsigned m_FFTSize;
596 SoundInput *m_soundInput;
597 Modulator *m_modulator;
598 SoundOutput *m_soundOutput;
599 NotificationAudio *m_notification;
600
601 // Configuration might one day offer to send a txDelayChanged signal.
602 // As long as it doesn't, we poll and compare with the previous value.
603 double m_TxDelay; // in seconds.
604
605 TxLoop *m_cq_loop;
606 TxLoop *m_hb_loop;
607
608 QThread m_networkThread;
609 QThread m_audioThread;
610 QThread m_notificationAudioThread;
611 JS8::Decoder m_decoder;
612
613 qint64 m_secBandChanged;
614
615 Frequency m_freqNominal;
616 Frequency m_freqTxNominal;
617
618 int m_freq;
619
620 qint32 m_XIT;
621 qint32 m_sec0;
622 qint32 m_RxLog;
623 qint32 m_nutc0;
624 // The period of the current submode, in seconds. (15 for normal, 10 for
625 // fast, ...)
626 qint32 m_TRperiod;
627 qint32 m_inGain;
628 qint32 m_idleMinutes;
629 qint32 m_nSubMode;
630 FrequencyList_v3::const_iterator m_frequency_list_fcal_iter;
631 qint32 m_i3bit;
632
633 bool m_btxok; // True if OK to transmit
634 bool m_decoderBusy;
635 QString m_decoderBusyBand;
636 QMap<qint32, qint32>
637 m_lastDecodeStartMap; // submode, decode k start position
638 QMap<qint32, qint32>
639 m_lastDecodeCycleMap; // JS8 40 & JS8 60 submodes, last enqueued cycle start
640 Radio::Frequency m_decoderBusyFreq;
641 QDateTime m_decoderBusyStartTime;
642 bool m_auto;
643 bool m_restart;
644 bool m_bDecoded;
645 int m_currentMessageType;
646 QString m_currentMessage;
647 int m_currentMessageBits;
648 int m_lastMessageType;
649 QString m_lastMessageSent;
650 bool m_tuneup;
651 bool m_isTimeToSend;
652
653 int m_ihsym;
654 float m_px;
655 float m_pxmax;
656 float m_df3;
657 quint32 m_iptt = 0;
658 quint32 m_iptt0;
659 bool m_btxok0;
660 double m_onAirFreq0;
661 bool m_first_error;
662
663 char m_msg[100][80];
664
665 // labels and widgets in status and header bar
666 QLabel tx_status_label;
667 QLabel config_label;
668 QLabel mode_label;
669 QLabel frequency_label;
670 QLabel auto_reply_label;
671 QLabel last_tx_label;
672 QLabel auto_tx_label;
673 QProgressBar progressBar;
674 QLabel wpm_label;
675 Styles::OffsetSliderWidget *freqOffsetWidget = nullptr;
676 int m_sliderFreqBeforeHB = 0;
677
678 // QPointer<QProcess> proc_js8;
679
680 QTimer m_guiTimer;
681 // Timer to switch off PTT after end of transmission.
682 QTimer pttReleaseTimer;
683 QTimer logQSOTimer;
684 QTimer tuneButtonTimer;
685 QTimer tuneATU_Timer;
686 QTimer TxAgainTimer;
687 QTimer minuteTimer;
688 QString m_baseCall;
689 QString m_hisCall;
690 QString m_hisGrid;
691 QString m_appDir;
692 QString m_palette;
693 QString m_rptSent;
694 QString m_rptRcvd;
695 QString m_msgSent0;
696 QString m_opCall;
697
698 struct CallDetail {
699 QString call;
700 QString through;
701 QString grid;
702 int dial;
703 int offset;
704 QDateTime cqTimestamp;
705 QDateTime ackTimestamp;
706 QDateTime utcTimestamp;
707 int snr;
708 int bits;
709 float tdrift;
710 int submode;
711 };
712
713 struct CommandDetail {
714 bool isCompound;
715 bool isBuffered;
716 QString from;
717 QString to;
718 QString cmd;
719 int dial;
720 int offset;
721 QDateTime utcTimestamp;
722 int snr;
723 int bits;
724 QString grid;
725 QString text;
726 QString extra;
727 float tdrift;
728 int submode;
729 QString relayPath;
730 };
731
732 struct ActivityDetail {
733 bool isLowConfidence;
734 bool isCompound;
735 bool isDirected;
736 bool isBuffered;
737 int bits;
738 int dial;
739 int offset;
740 QString text;
741 QDateTime utcTimestamp;
742 int snr;
743 bool shouldDisplay;
744 float tdrift;
745 int submode;
746 };
747
748 struct MessageBuffer {
749 CommandDetail cmd;
750 QQueue<CallDetail> compound;
752 };
753
754 QString m_prevSelectedCallsign;
755 int m_bandActivityWidth;
756 int m_callActivityWidth;
757 int m_textActivityWidth;
758 int m_waterfallHeight;
759 bool m_bandActivityWasVisible;
760 bool m_rxDirty;
761 bool m_rxDisplayDirty;
762 int m_txFrameCountEstimate;
763 int m_txFrameCount;
764 int m_txFrameCountSent;
765 QTimer m_txTextDirtyDebounce;
766 bool m_txTextDirty;
767 QString m_txTextDirtyLastText;
768 QString m_txTextDirtyLastSelectedCall;
769 QString m_lastTxMessage;
770 QString m_totalTxMessage;
771
772 // moved from mainwindow.cpp, is used in multiple functions
773 QString since(QDateTime const &time) {
774 auto const delta = time.secsTo(DriftingDateTime::currentDateTimeUtc());
775
776 if (delta >= 60 * 60 * 24)
777 return QString("%1d").arg(delta / (60 * 60 * 24));
778 else if (delta >= 60 * 60)
779 return QString("%1h").arg(delta / (60 * 60));
780 else if (delta >= 60)
781 return QString("%1m").arg(delta / (60));
782 else if (delta >= 15)
783 return QString("%1s").arg(delta - (delta % 15));
784 else
785 return QString("now");
786 }
787
788 QDateTime m_lastTxStartTime;
789 QDateTime m_lastTxStopTime;
790 qint32 m_driftMsMMA;
791 qint32 m_driftMsMMA_N;
792
793 // moved from mainwindow.cpp, is used in multiple functions
794 auto replaceMacros(QString const &text,
795 QMap<QString, QString> const &values, bool const prune) {
796 QString output = text;
797
798 for (auto const [key, value] : values.asKeyValueRange()) {
799 output = output.replace(key, value.toUpper());
800 }
801
802 return prune ? output.replace(QRegularExpression("[<](?:[^>]+)[>]"), "")
803 : output;
804 }
805
806 QList<int> generateOffsets(int minOffset, int maxOffset) {
807 QList<int> offsets;
808
809 // TODO: these offsets aren't ordered correctly...
810
811 for (int i = minOffset; i <= maxOffset; i++) {
812 offsets.append(i);
813 }
814 return offsets;
815 }
816
817 enum Priority {
818 PriorityLow = 10,
819 PriorityNormal = 100,
820 PriorityHigh = 1000
821 };
822
823 struct PrioritizedMessage {
824 QDateTime date;
825 int priority;
826 QString message;
827 int offset;
828 Callback callback;
829
830 friend bool operator<(PrioritizedMessage const &a,
831 PrioritizedMessage const &b) {
832 if (a.priority < b.priority) {
833 return true;
834 }
835 return a.date < b.date;
836 }
837 };
838
839 struct CachedDirectedType {
840 bool isAllcall;
841 QDateTime date;
842 };
843
844 struct DecodeParams {
845 int submode;
846 int start;
847 int sz;
848 };
849
850 struct FrameCacheKey {
851 int submode;
852 QString frame;
853
854 FrameCacheKey(int submode, QString frame)
855 : submode(submode), frame(std::move(frame)) {}
856
857 bool operator==(FrameCacheKey const &) const noexcept = default;
858
859 struct Hash {
860 std::size_t operator()(FrameCacheKey const &key) const noexcept {
861 std::size_t const h1 = std::hash<int>{}(key.submode);
862 std::size_t const h2 = qHash(key.frame);
863 return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));
864 }
865 };
866 };
867
868 using FrameCache =
869 std::unordered_map<FrameCacheKey, QDateTime, FrameCacheKey::Hash>;
870 using BandActivity = QMap<int, QList<ActivityDetail>>;
871
872 QQueue<DecodeParams> m_decoderQueue;
873 FrameCache m_messageDupeCache; // submode, frame -> date seen
874 QVariantMap m_showColumnsCache; // table column:key -> show boolean
875 QVariantMap m_sortCache; // table key -> sort by
876 QPriorityQueue<PrioritizedMessage> m_txMessageQueue; // messages to be sent
877 QQueue<QPair<QString, int>> m_txFrameQueue; // frames to be sent
878 QQueue<ActivityDetail> m_rxActivityQueue; // all rx activity queue
879 QQueue<CommandDetail>
880 m_rxCommandQueue; // command queue for processing commands
881 QQueue<CallDetail>
882 m_rxCallQueue; // call detail queue for spots to pskreporter
883 QMap<QString, QString>
884 m_compoundCallCache; // base callsign -> compound callsign
885 QCache<QString, QDateTime> m_txAllcallCommandCache; // callsign -> last tx
886 QCache<int, QDateTime> m_rxRecentCache; // freq -> last rx
887 QCache<int, CachedDirectedType>
888 m_rxDirectedCache; // freq -> last directed rx
889 QCache<QString, int> m_rxCallCache; // call -> last freq seen
890 QMap<int, int> m_rxFrameBlockNumbers; // freq -> block
891 BandActivity m_bandActivity; // freq -> [(text, last timestamp), ...]
892 QMap<int, MessageBuffer> m_messageBuffer; // freq -> (cmd, [frames, ...])
893 int m_lastClosedMessageBufferOffset;
894 QMap<QString, CallDetail>
895 m_callActivity; // call -> (last freq, last timestamp)
896
897 QMap<int, QString> m_origRxHeaderLabelMap; // colIndex, label
898 QMap<int, QString> m_origCallActivityHeaderLabelMap; // colIndex, label
899 QMap<QString, QString> m_columnLabelMap; // full, minimal
900
901 QMap<QString, QSet<QString>>
902 m_heardGraphOutgoing; // callsign -> [stations who've this callsign has
903 // heard]
904 QMap<QString, QSet<QString>>
905 m_heardGraphIncoming; // callsign -> [stations who've heard this
906 // callsign]
907
908 QMap<QString, int> m_rxInboxCountCache; // call -> count
909
910 QMap<QString, QMap<QString, CallDetail>>
911 m_callActivityBandCache; // band -> call activity
912 QMap<QString, QMap<int, QList<ActivityDetail>>>
913 m_bandActivityBandCache; // band -> band activity
914 QMap<QString, QString> m_rxTextBandCache; // band -> rx text
915 QMap<QString, QMap<QString, QSet<QString>>>
916 m_heardGraphOutgoingBandCache; // band -> heard in
917 QMap<QString, QMap<QString, QSet<QString>>>
918 m_heardGraphIncomingBandCache; // band -> heard out
919
920 // Pending autoreply confirmations (network API and local UI notification)
921 struct PendingConfirmation {
922 int id;
923 int priority;
924 QString message;
925 int offset;
926 Callback callback;
927 QTimer *timer;
929 };
930 int m_nextConfirmId = 0;
931 QMap<int, PendingConfirmation> m_pendingConfirmations;
932
933 QMap<QString, QDateTime>
934 m_callSelectedTime; // call -> timestamp when callsign was last selected
939 QHash<QString, QDateTime> m_aprsRelayDedupCache;
940 QSet<QString> m_callSeenHeartbeat; // call
941 bool m_bandHopped;
942 Frequency m_bandHoppedFreq;
943
945 int m_hbInterval;
947 int m_cqInterval;
948
950 bool m_hbPaused;
951
952 QDateTime m_dateTimeQSOOn;
953 QDateTime m_dateTimeLastTX;
954
955 QSet<int> m_rxBlockedOffsets; //callsign blocking
956
957 LogBook m_logBook;
958 unsigned m_msAudioOutputBuffered;
959 unsigned m_framesAudioInputBuffered;
960 QThread::Priority m_audioThreadPriority;
961 QThread::Priority m_notificationAudioThreadPriority;
962 QThread::Priority m_decoderThreadPriority;
963 QThread::Priority m_networkThreadPriority;
964 bool m_splitMode;
965 bool m_monitoring;
966 bool m_generateAudioWhenPttConfirmedByTX;
967 bool m_transmitting;
968 bool m_tune;
969 bool m_tx_watchdog; // true when watchdog triggered
970 bool m_block_pwr_tooltip;
971 bool m_PwrBandSetOK;
972 Frequency m_lastMonitoredFrequency;
973 MessageClient *m_messageClient;
974 MessageServer *m_messageServer;
975 WSJTXMessageClient *m_wsjtxMessageClient;
976 WSJTXMessageMapper *m_wsjtxMessageMapper;
977 TCPClient *m_n3fjpClient;
978 PSKReporter *m_pskReporter;
979 SpotClient *m_spotClient;
980 APRSISClient *m_aprsClient;
981 AprsInboundRelay *m_aprsInboundRelay;
982 QVariantHash m_pwrBandTxMemory; // Remembers power level by band
983 QVariantHash
984 m_pwrBandTuneMemory; // Remembers power level by band for tuning
985 QByteArray m_geometryNoControls;
986
987 //---------------------------------------------------- private functions
988 void readSettings();
989 void set_application_font(QFont const &);
990 void writeSettings();
991 void createStatusBar();
992 void statusChanged();
993 void rigFailure(QString const &reason);
994 void spotSetLocal();
995 void pskSetLocal();
996 void aprsSetLocal();
997 void spotReport(int submode, int dial, int offset, int snr,
998 QString const &callsign, QString const &grid);
999 void spotCmd(CommandDetail const &cmd);
1000 void spotAprsCmd(CommandDetail const &cmd);
1001 void pskLogReport(QString const &mode, int dial, int offset, int snr,
1002 QString const &callsign, QString const &grid,
1003 QDateTime const &utcTimestamp);
1004 void spotAprsGrid(int dial, int offset, int snr, QString callsign,
1005 QString grid);
1006 Radio::Frequency dialFrequency();
1007 void setSubmode(int submode);
1008 void updateCurrentBand();
1009 void displayDialFrequency();
1010 void transmitDisplay(bool);
1011 void postDecode(bool is_new, QString const &message);
1012 void displayTransmit();
1013 void updateModeButtonText();
1014 void updateButtonDisplay();
1015 void updateTextDisplay();
1016 void updateTextWordCheckerDisplay();
1017 void updateTextStatsDisplay(QString text, int count);
1018 void updateTxButtonDisplay();
1019 bool isMyCallIncluded(QString const &text);
1020 bool isAllCallIncluded(QString const &text);
1021 bool isGroupCallIncluded(const QString &text);
1022 QString callsignSelected(bool useInputText = false);
1023 void callsignSelectedChanged(QString old, QString current);
1024 bool isRecentOffset(int submode, int offset);
1025 void markOffsetRecent(int offset);
1026 bool isDirectedOffset(int offset, bool *pIsAllCall);
1027 void markOffsetDirected(int offset, bool isAllCall);
1028 void clearOffsetDirected(int offset);
1029 void processActivity(bool force = false);
1030 void resetTimeDeltaAverage();
1031 void processRxActivity(); // JS8_Mainwindow/processRxActivity.cpp
1032 void processIdleActivity();
1033 void processCompoundActivity();
1034 void processBufferedActivity(); // JS8_Mainwindow/processBufferedActivity.cpp
1035 void processCommandActivity(); // JS8_Mainwindow/processCommandActivity.cpp
1036 void processHeartbeatRateLimit(const QString &callsign); // JS8_Mainwindow/processHeartbeatRateLimit.cpp
1037 QString inboxPath();
1038 QString hbBlockingPath() const;
1039 void refreshInboxCounts();
1040 bool hasMessageHistory(QString call);
1041 int addCommandToMyInbox(CommandDetail d);
1042 int addCommandToStorage(QString type, CommandDetail d);
1043 int getNextMessageIdForCallsign(QString callsign);
1044 int getLookaheadMessageIdForCallsign(QString callsign, int afterMsgId);
1045 int getNextGroupMessageIdForCallsign(QString group_name, QString callsign);
1046 int getLookaheadGroupMessageIdForCallsign(QString group_name,
1047 QString callsign, int afterMsgId);
1048 int countUnreadForCallsign(const QString &callsign);
1049 int countGroupUnreadForCallsign(const QString &group_name,
1050 const QString &callsign);
1051 bool markGroupMsgDeliveredForCallsign(int msgId, QString callsign);
1052 bool markMsgDelivered(int mid, Message msg);
1053 QStringList parseRelayPathCallsigns(QString from, QString text);
1054 void processSpots();
1055 void processTxQueue();
1056 void displayActivity(bool force = false);
1057 void displayBandActivity(); // JS8_Mainwindow/displayBandActivity.cpp
1058 void displayCallActivity(); // JS8_Mainwindow/displayCallActivity.cpp
1059 void enable_DXCC_entity(bool on);
1060 void setRig(Frequency = 0); // zero frequency means no change
1061 QDateTime nextTransmitCycle();
1062 void statusUpdate();
1063 void on_the_minute();
1064 void tryBandHop();
1065 void add_child_to_event_filter(QObject *);
1066 void remove_child_from_event_filter(QObject *);
1067 void setup_status_bar();
1068 QString columnLabel(QString defaultLabel);
1069 void ensureMessageDock();
1070
1071 void resetIdleTimer();
1072 void incrementIdleTimer();
1073 void tx_watchdog(bool triggered);
1074 void write_frequency_entry(QString const &file_name);
1075 void write_transmit_entry(QString const &file_name);
1076};
1077
1078#endif // MAINWINDOW_H
APRS-IS client interface for JS8Call.
Defines the inbound APRS-IS relay handler for JS8Call.
Pill-shaped visual highlights for directed message tokens.
Definition ADIF.h:18
APRS-IS client responsible for sending and receiving APRS frames.
Definition APRSISClient.h:21
Handles inbound APRS-IS messages and enqueues JS8 relays.
Definition AprsInboundRelay.h:20
Definition AudioDevice.h:11
Definition Configuration.h:59
Definition DecodedText.h:16
Definition Detector.h:15
Definition FrequencyList.h:67
Definition HelpTextWindow.h:9
Definition JS8MessageBox.h:13
Definition JS8.h:86
Definition JSC_checker.h:12
Definition LogBook.h:19
Definition LogQSO.h:22
Definition MessageClient.h:21
Definition MessagePanel.h:12
Definition MessageServer.h:14
Definition Message.h:16
Definition Modulator.h:20
Definition MultiSettings.h:62
Definition NetworkAccessManager.h:18
Definition NotificationAudio.h:15
Definition PSKReporter.h:13
Definition qpriorityqueue.h:39
Definition qpriorityqueue.h:72
Definition SelfDestructMessageBox.h:10
Definition SoundInput.h:16
Definition SoundOutput.h:13
Definition SpotClient.h:9
Definition styles.h:713
Definition TCPClient.h:9
Definition Transceiver.h:83
Definition Transceiver.h:50
Definition TxLoop.h:10
void confirmThenEnqueueMessage(int timeout, int priority, QString message, int offset, Callback c)
Presents a local confirmation dialog and fires a network confirmation request.
Definition confirmThenEnqueueMessage.cpp:34
void dataSink(qint64 frames)
Definition dataSink.cpp:79
void guiUpdate()
Definition mainwindow.cpp:2698
void resetMessageTransmitQueue()
Resets the frame-level transmission state after a message completes.
Definition mainwindow.cpp:3510
UI_Constructor(QString const &program_info, QDir const &temp_directory, bool multiple, MultiSettings *settings, QWidget *parent=nullptr)
Definition UI_Constructor.cpp:20
void processDecodeEvent(JS8::Event::Variant const &)
Definition processDecodeEvent.cpp:10
Definition WSJTXMessageClient.h:17
Maps JS8Call events to WSJT-X protocol messages.
Definition WSJTXMessageMapper.h:21
Definition WideGraph.h:29
Definition StationList.h:50
Definition mainwindow.h:859
header file that defines platform specific label, button, widget and dialog styles used in functions ...