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