Merge branch 'feat-dropped-frames' into develop

This commit is contained in:
Bill Somerville 2020-08-16 03:35:10 +01:00
commit c99f236dca
No known key found for this signature in database
GPG Key ID: D864B06D1E81618F
26 changed files with 1653 additions and 1384 deletions

6
.gitignore vendored
View File

@ -1,6 +1,9 @@
~* ~*
TAGS TAGS
tags tags
GPATH
GRTAGS
GTAGS
*~ *~
junk* junk*
jnq* jnq*
@ -9,6 +12,9 @@ jnq*
*.mod *.mod
*.pro.user *.pro.user
*.txt *.txt
*.bak
!**/CMakeLists.txt
__pycache__
cmake-build-debug cmake-build-debug
cmake-build-release cmake-build-release
CMakeFiles CMakeFiles

View File

@ -41,7 +41,8 @@ bool SoundInput::audioError () const
return result; return result;
} }
void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, AudioDevice * sink, unsigned downSampleFactor, AudioDevice::Channel channel) void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, AudioDevice * sink
, unsigned downSampleFactor, AudioDevice::Channel channel)
{ {
Q_ASSERT (sink); Q_ASSERT (sink);
@ -62,8 +63,7 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi
Q_EMIT error (tr ("Requested input audio format is not valid.")); Q_EMIT error (tr ("Requested input audio format is not valid."));
return; return;
} }
else if (!device.isFormatSupported (format))
if (!device.isFormatSupported (format))
{ {
// qDebug () << "Nearest supported audio format:" << device.nearestFormat (format); // qDebug () << "Nearest supported audio format:" << device.nearestFormat (format);
Q_EMIT error (tr ("Requested input audio format is not supported on device.")); Q_EMIT error (tr ("Requested input audio format is not supported on device."));
@ -79,11 +79,20 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi
connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged); connect (m_stream.data(), &QAudioInput::stateChanged, this, &SoundInput::handleStateChanged);
m_stream->setBufferSize (m_stream->format ().bytesForFrames (framesPerBuffer)); //qDebug () << "SoundIn default buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
// the Windows MME version of QAudioInput uses 1/5 of the buffer
// size for period size other platforms seem to optimize themselves
#if defined (Q_OS_WIN)
m_stream->setBufferSize (m_stream->format ().bytesForFrames (framesPerBuffer * 5));
#else
Q_UNUSED (framesPerBuffer);
#endif
if (sink->initialize (QIODevice::WriteOnly, channel)) if (sink->initialize (QIODevice::WriteOnly, channel))
{ {
m_stream->start (sink); m_stream->start (sink);
audioError (); audioError ();
cummulative_lost_usec_ = -1;
//qDebug () << "SoundIn selected buffer size (bytes):" << m_stream->bufferSize () << "peirod size:" << m_stream->periodSize ();
} }
else else
{ {
@ -115,7 +124,7 @@ void SoundInput::resume ()
} }
} }
void SoundInput::handleStateChanged (QAudio::State newState) const void SoundInput::handleStateChanged (QAudio::State newState)
{ {
//qDebug () << "SoundInput::handleStateChanged: newState:" << newState; //qDebug () << "SoundInput::handleStateChanged: newState:" << newState;
@ -126,6 +135,7 @@ void SoundInput::handleStateChanged (QAudio::State newState) const
break; break;
case QAudio::ActiveState: case QAudio::ActiveState:
reset (false);
Q_EMIT status (tr ("Receiving")); Q_EMIT status (tr ("Receiving"));
break; break;
@ -152,6 +162,22 @@ void SoundInput::handleStateChanged (QAudio::State newState) const
} }
} }
void SoundInput::reset (bool report_dropped_frames)
{
if (m_stream)
{
if (cummulative_lost_usec_ >= 0 // don't report first time as we
// don't yet known latency
&& report_dropped_frames)
{
auto lost_usec = m_stream->elapsedUSecs () - m_stream->processedUSecs () - cummulative_lost_usec_;
Q_EMIT dropped_frames (m_stream->format ().framesForDuration (lost_usec), lost_usec);
//qDebug () << "SoundInput::reset: frames dropped:" << m_stream->format ().framesForDuration (lost_usec) << "sec:" << lost_usec / 1.e6;
}
cummulative_lost_usec_ = m_stream->elapsedUSecs () - m_stream->processedUSecs ();
}
}
void SoundInput::stop() void SoundInput::stop()
{ {
if (m_stream) if (m_stream)

View File

@ -24,6 +24,7 @@ public:
SoundInput (QObject * parent = nullptr) SoundInput (QObject * parent = nullptr)
: QObject {parent} : QObject {parent}
, m_sink {nullptr} , m_sink {nullptr}
, cummulative_lost_usec_ {0}
{ {
} }
@ -35,18 +36,21 @@ public:
Q_SLOT void suspend (); Q_SLOT void suspend ();
Q_SLOT void resume (); Q_SLOT void resume ();
Q_SLOT void stop (); Q_SLOT void stop ();
Q_SLOT void reset (bool report_dropped_frames);
Q_SIGNAL void error (QString message) const; Q_SIGNAL void error (QString message) const;
Q_SIGNAL void status (QString message) const; Q_SIGNAL void status (QString message) const;
Q_SIGNAL void dropped_frames (qint32 dropped, qint64 usec);
private: private:
// used internally // used internally
Q_SLOT void handleStateChanged (QAudio::State) const; Q_SLOT void handleStateChanged (QAudio::State);
bool audioError () const; bool audioError () const;
QScopedPointer<QAudioInput> m_stream; QScopedPointer<QAudioInput> m_stream;
QPointer<AudioDevice> m_sink; QPointer<AudioDevice> m_sink;
qint64 cummulative_lost_usec_;
}; };
#endif #endif

View File

@ -9,15 +9,6 @@
#include "moc_soundout.cpp" #include "moc_soundout.cpp"
/*
#if defined (WIN32)
# define MS_BUFFERED 1000u
#else
# define MS_BUFFERED 2000u
#endif
*/
# define MS_BUFFERED 200u
bool SoundOutput::audioError () const bool SoundOutput::audioError () const
{ {
bool result (true); bool result (true);
@ -50,11 +41,13 @@ bool SoundOutput::audioError () const
return result; return result;
} }
void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered) void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered)
{
if (!device.isNull ())
{ {
Q_ASSERT (0 < channels && channels < 3); Q_ASSERT (0 < channels && channels < 3);
m_msBuffered = msBuffered; m_framesBuffered = frames_buffered;
QAudioFormat format (device.preferredFormat ()); QAudioFormat format (device.preferredFormat ());
// qDebug () << "Preferred audio output format:" << format; // qDebug () << "Preferred audio output format:" << format;
@ -68,44 +61,56 @@ void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels,
{ {
Q_EMIT error (tr ("Requested output audio format is not valid.")); Q_EMIT error (tr ("Requested output audio format is not valid."));
} }
if (!device.isFormatSupported (format)) else if (!device.isFormatSupported (format))
{ {
Q_EMIT error (tr ("Requested output audio format is not supported on device.")); Q_EMIT error (tr ("Requested output audio format is not supported on device."));
} }
else
{
// qDebug () << "Selected audio output format:" << format; // qDebug () << "Selected audio output format:" << format;
m_stream.reset (new QAudioOutput (device, format)); m_stream.reset (new QAudioOutput (device, format));
audioError (); audioError ();
m_stream->setVolume (m_volume); m_stream->setVolume (m_volume);
m_stream->setNotifyInterval(100); m_stream->setNotifyInterval(100);
error_ = false;
connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged); connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged);
// qDebug() << "A" << m_volume << m_stream->notifyInterval(); // qDebug() << "A" << m_volume << m_stream->notifyInterval();
} }
}
}
void SoundOutput::restart (QIODevice * source) void SoundOutput::restart (QIODevice * source)
{ {
Q_ASSERT (m_stream); if (!m_stream)
{
if (!error_)
{
error_ = true; // only signal error once
Q_EMIT error (tr ("No audio output device configured."));
}
return;
}
else
{
error_ = false;
}
//
// This buffer size is critical since for proper sound streaming. If
// it is too short; high activity levels on the machine can starve
// the audio buffer. On the other hand the Windows implementation
// seems to take the length of the buffer in time to stop the audio
// stream even if reset() is used.
//
// 2 seconds seems a reasonable compromise except for Windows
// where things are probably broken.
//
// we have to set this before every start on the stream because the // we have to set this before every start on the stream because the
// Windows implementation seems to forget the buffer size after a // Windows implementation seems to forget the buffer size after a
// stop. // stop.
m_stream->setBufferSize (m_stream->format().bytesForDuration((m_msBuffered ? m_msBuffered : MS_BUFFERED) * 1000)); //qDebug () << "SoundOut default buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
// qDebug() << "B" << m_stream->bufferSize() << if (m_framesBuffered)
// m_stream->periodSize() << m_stream->notifyInterval(); {
#if defined (Q_OS_WIN)
m_stream->setBufferSize (m_stream->format().bytesForFrames (m_framesBuffered));
#endif
}
m_stream->setCategory ("production"); m_stream->setCategory ("production");
m_stream->start (source); m_stream->start (source);
// qDebug () << "SoundOut selected buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
} }
void SoundOutput::suspend () void SoundOutput::suspend ()

View File

@ -18,15 +18,16 @@ class SoundOutput
public: public:
SoundOutput () SoundOutput ()
: m_msBuffered {0u} : m_framesBuffered {0}
, m_volume {1.0} , m_volume {1.0}
, error_ {false}
{ {
} }
qreal attenuation () const; qreal attenuation () const;
public Q_SLOTS: public Q_SLOTS:
void setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered = 0u); void setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered = 0);
void restart (QIODevice *); void restart (QIODevice *);
void suspend (); void suspend ();
void resume (); void resume ();
@ -47,8 +48,9 @@ private Q_SLOTS:
private: private:
QScopedPointer<QAudioOutput> m_stream; QScopedPointer<QAudioOutput> m_stream;
unsigned m_msBuffered; int m_framesBuffered;
qreal m_volume; qreal m_volume;
bool error_;
}; };
#endif #endif

View File

@ -222,9 +222,12 @@ set (WSJT_QT_CONF_DESTINATION ${QT_CONF_DESTINATION} CACHE PATH "Path for the qt
# #
# Project sources # Project sources
# #
set (fort_qt_CXXSRCS
lib/shmem.cpp
)
set (wsjt_qt_CXXSRCS set (wsjt_qt_CXXSRCS
qt_helpers.cpp qt_helpers.cpp
lib/shmem.cpp
widgets/MessageBox.cpp widgets/MessageBox.cpp
MetaDataRegistry.cpp MetaDataRegistry.cpp
Network/NetworkServerLookup.cpp Network/NetworkServerLookup.cpp
@ -730,6 +733,7 @@ set (qcp_CXXSRCS
set (all_CXXSRCS set (all_CXXSRCS
${wsjt_CXXSRCS} ${wsjt_CXXSRCS}
${fort_qt_CXXSRCS}
${wsjt_qt_CXXSRCS} ${wsjt_qt_CXXSRCS}
${wsjt_qtmm_CXXSRCS} ${wsjt_qtmm_CXXSRCS}
${wsjtx_CXXSRCS} ${wsjtx_CXXSRCS}
@ -744,7 +748,6 @@ set (all_C_and_CXXSRCS
) )
set (TOP_LEVEL_RESOURCES set (TOP_LEVEL_RESOURCES
cty.dat
icons/Darwin/wsjtx.iconset/icon_128x128.png icons/Darwin/wsjtx.iconset/icon_128x128.png
contrib/gpl-v3-logo.svg contrib/gpl-v3-logo.svg
artwork/splash.png artwork/splash.png
@ -926,7 +929,9 @@ endif ()
if (WSJT_GENERATE_DOCS) if (WSJT_GENERATE_DOCS)
add_subdirectory (doc) add_subdirectory (doc)
endif (WSJT_GENERATE_DOCS) endif (WSJT_GENERATE_DOCS)
if (EXISTS ${CMAKE_SOURCE_DIR}/tests AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/tests)
add_subdirectory (tests)
endif ()
# #
# Library building setup # Library building setup
@ -1256,6 +1261,11 @@ if (WIN32)
target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase) target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase)
endif (WIN32) endif (WIN32)
# build a library of package Qt functionality used in Fortran utilities
add_library (fort_qt STATIC ${fort_qt_CXXSRCS})
target_link_libraries (fort_qt Qt5::Core)
# build a library of WSJT Qt multimedia components
add_library (wsjt_qtmm STATIC ${wsjt_qtmm_CXXSRCS} ${wsjt_qtmm_GENUISRCS}) add_library (wsjt_qtmm STATIC ${wsjt_qtmm_CXXSRCS} ${wsjt_qtmm_GENUISRCS})
target_link_libraries (wsjt_qtmm Qt5::Multimedia) target_link_libraries (wsjt_qtmm Qt5::Multimedia)
@ -1303,9 +1313,9 @@ if (${OPENMP_FOUND} OR APPLE)
LINK_FLAGS -Wl,--stack,16777216 LINK_FLAGS -Wl,--stack,16777216
) )
endif () endif ()
target_link_libraries (jt9 wsjt_fort_omp wsjt_cxx wsjt_qt) target_link_libraries (jt9 wsjt_fort_omp wsjt_cxx fort_qt)
else (${OPENMP_FOUND} OR APPLE) else (${OPENMP_FOUND} OR APPLE)
target_link_libraries (jt9 wsjt_fort wsjt_cxx Qt5::Core) target_link_libraries (jt9 wsjt_fort wsjt_cxx fort_qt)
endif (${OPENMP_FOUND} OR APPLE) endif (${OPENMP_FOUND} OR APPLE)
if(WSJT_BUILD_UTILS) if(WSJT_BUILD_UTILS)
@ -1563,6 +1573,7 @@ install (FILES
) )
install (FILES install (FILES
cty.dat
contrib/Ephemeris/JPLEPH contrib/Ephemeris/JPLEPH
DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME}
#COMPONENT runtime #COMPONENT runtime

View File

@ -137,6 +137,8 @@
#include <QApplication> #include <QApplication>
#include <QMetaType> #include <QMetaType>
#include <QList> #include <QList>
#include <QPair>
#include <QVariant>
#include <QSettings> #include <QSettings>
#include <QAudioDeviceInfo> #include <QAudioDeviceInfo>
#include <QAudioInput> #include <QAudioInput>
@ -401,6 +403,7 @@ class Configuration::impl final
public: public:
using FrequencyDelta = Radio::FrequencyDelta; using FrequencyDelta = Radio::FrequencyDelta;
using port_type = Configuration::port_type; using port_type = Configuration::port_type;
using audio_info_type = QPair<QAudioDeviceInfo, QList<QVariant> >;
explicit impl (Configuration * self explicit impl (Configuration * self
, QNetworkAccessManager * network_manager , QNetworkAccessManager * network_manager
@ -429,9 +432,14 @@ private:
void read_settings (); void read_settings ();
void write_settings (); void write_settings ();
bool load_audio_devices (QAudio::Mode, QComboBox *, QAudioDeviceInfo *); Q_SLOT void lazy_models_load (int);
void find_audio_devices ();
QAudioDeviceInfo find_audio_device (QAudio::Mode, QComboBox *, QString const& device_name);
void load_audio_devices (QAudio::Mode, QComboBox *, QAudioDeviceInfo *);
void update_audio_channels (QComboBox const *, int, QComboBox *, bool); void update_audio_channels (QComboBox const *, int, QComboBox *, bool);
void find_tab (QWidget *);
void initialize_models (); void initialize_models ();
bool split_mode () const bool split_mode () const
{ {
@ -477,8 +485,6 @@ private:
Q_SLOT void on_force_DTR_combo_box_currentIndexChanged (int); Q_SLOT void on_force_DTR_combo_box_currentIndexChanged (int);
Q_SLOT void on_force_RTS_combo_box_currentIndexChanged (int); Q_SLOT void on_force_RTS_combo_box_currentIndexChanged (int);
Q_SLOT void on_rig_combo_box_currentIndexChanged (int); Q_SLOT void on_rig_combo_box_currentIndexChanged (int);
Q_SLOT void on_sound_input_combo_box_currentTextChanged (QString const&);
Q_SLOT void on_sound_output_combo_box_currentTextChanged (QString const&);
Q_SLOT void on_add_macro_push_button_clicked (bool = false); Q_SLOT void on_add_macro_push_button_clicked (bool = false);
Q_SLOT void on_delete_macro_push_button_clicked (bool = false); Q_SLOT void on_delete_macro_push_button_clicked (bool = false);
Q_SLOT void on_PTT_method_button_group_buttonClicked (int); Q_SLOT void on_PTT_method_button_group_buttonClicked (int);
@ -647,10 +653,8 @@ private:
bool pwrBandTuneMemory_; bool pwrBandTuneMemory_;
QAudioDeviceInfo audio_input_device_; QAudioDeviceInfo audio_input_device_;
bool default_audio_input_device_selected_;
AudioDevice::Channel audio_input_channel_; AudioDevice::Channel audio_input_channel_;
QAudioDeviceInfo audio_output_device_; QAudioDeviceInfo audio_output_device_;
bool default_audio_output_device_selected_;
AudioDevice::Channel audio_output_channel_; AudioDevice::Channel audio_output_channel_;
friend class Configuration; friend class Configuration;
@ -976,8 +980,6 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
, transceiver_command_number_ {0} , transceiver_command_number_ {0}
, degrade_ {0.} // initialize to zero each run, not , degrade_ {0.} // initialize to zero each run, not
// saved in settings // saved in settings
, default_audio_input_device_selected_ {false}
, default_audio_output_device_selected_ {false}
{ {
ui_->setupUi (this); ui_->setupUi (this);
@ -1100,6 +1102,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
// //
// setup hooks to keep audio channels aligned with devices // setup hooks to keep audio channels aligned with devices
// //
connect (ui_->configuration_tabs, &QTabWidget::currentChanged, this, &Configuration::impl::lazy_models_load);
{ {
using namespace std; using namespace std;
using namespace std::placeholders; using namespace std::placeholders;
@ -1130,7 +1133,9 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
ui_->frequencies_table_view->setModel (&next_frequencies_); ui_->frequencies_table_view->setModel (&next_frequencies_);
ui_->frequencies_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); ui_->frequencies_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
ui_->frequencies_table_view->horizontalHeader ()->setResizeContentsPrecision (0);
ui_->frequencies_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); ui_->frequencies_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
ui_->frequencies_table_view->verticalHeader ()->setResizeContentsPrecision (0);
ui_->frequencies_table_view->sortByColumn (FrequencyList_v2::frequency_column, Qt::AscendingOrder); ui_->frequencies_table_view->sortByColumn (FrequencyList_v2::frequency_column, Qt::AscendingOrder);
ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2::frequency_mhz_column, true); ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2::frequency_mhz_column, true);
@ -1170,7 +1175,9 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
stations_.sort (StationList::band_column); stations_.sort (StationList::band_column);
ui_->stations_table_view->setModel (&next_stations_); ui_->stations_table_view->setModel (&next_stations_);
ui_->stations_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); ui_->stations_table_view->horizontalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
ui_->stations_table_view->horizontalHeader ()->setResizeContentsPrecision (0);
ui_->stations_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents); ui_->stations_table_view->verticalHeader ()->setSectionResizeMode (QHeaderView::ResizeToContents);
ui_->stations_table_view->verticalHeader ()->setResizeContentsPrecision (0);
ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder); ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder);
// stations delegates // stations delegates
@ -1189,20 +1196,8 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network
// //
ui_->highlighting_list_view->setModel (&next_decode_highlighing_model_); ui_->highlighting_list_view->setModel (&next_decode_highlighing_model_);
//
// load combo boxes with audio setup choices
//
default_audio_input_device_selected_ = load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &audio_input_device_);
default_audio_output_device_selected_ = load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &audio_output_device_);
update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false);
update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true);
ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_);
ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_);
enumerate_rigs (); enumerate_rigs ();
initialize_models (); // initialize_models ();
transceiver_thread_ = new QThread {this}; transceiver_thread_ = new QThread {this};
transceiver_thread_->start (); transceiver_thread_->start ();
@ -1215,8 +1210,35 @@ Configuration::impl::~impl ()
write_settings (); write_settings ();
} }
void Configuration::impl::lazy_models_load (int current_tab_index)
{
switch (current_tab_index)
{
case 2: // Audio
//
// load combo boxes with audio setup choices
//
load_audio_devices (QAudio::AudioInput, ui_->sound_input_combo_box, &audio_input_device_);
load_audio_devices (QAudio::AudioOutput, ui_->sound_output_combo_box, &audio_output_device_);
update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false);
update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true);
ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_);
ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_);
break;
default:
break;
}
}
void Configuration::impl::initialize_models () void Configuration::impl::initialize_models ()
{ {
{
SettingsGroup g {settings_, "Configuration"};
find_audio_devices ();
}
auto pal = ui_->callsign_line_edit->palette (); auto pal = ui_->callsign_line_edit->palette ();
if (my_callsign_.isEmpty ()) if (my_callsign_.isEmpty ())
{ {
@ -1238,6 +1260,7 @@ void Configuration::impl::initialize_models ()
ui_->sbDegrade->setValue (degrade_); ui_->sbDegrade->setValue (degrade_);
ui_->sbBandwidth->setValue (RxBandwidth_); ui_->sbBandwidth->setValue (RxBandwidth_);
ui_->PTT_method_button_group->button (rig_params_.ptt_type)->setChecked (true); ui_->PTT_method_button_group->button (rig_params_.ptt_type)->setChecked (true);
ui_->save_path_display_label->setText (save_directory_.absolutePath ()); ui_->save_path_display_label->setText (save_directory_.absolutePath ());
ui_->azel_path_display_label->setText (azel_directory_.absolutePath ()); ui_->azel_path_display_label->setText (azel_directory_.absolutePath ());
ui_->CW_id_after_73_check_box->setChecked (id_after_73_); ui_->CW_id_after_73_check_box->setChecked (id_after_73_);
@ -1390,61 +1413,7 @@ void Configuration::impl::read_settings ()
save_directory_.setPath (settings_->value ("SaveDir", default_save_directory_.absolutePath ()).toString ()); save_directory_.setPath (settings_->value ("SaveDir", default_save_directory_.absolutePath ()).toString ());
azel_directory_.setPath (settings_->value ("AzElDir", default_azel_directory_.absolutePath ()).toString ()); azel_directory_.setPath (settings_->value ("AzElDir", default_azel_directory_.absolutePath ()).toString ());
{ find_audio_devices ();
//
// retrieve audio input device
//
auto saved_name = settings_->value ("SoundInName").toString ();
// deal with special Windows default audio devices
auto default_device = QAudioDeviceInfo::defaultInputDevice ();
if (saved_name == default_device.deviceName ())
{
audio_input_device_ = default_device;
default_audio_input_device_selected_ = true;
}
else
{
default_audio_input_device_selected_ = false;
Q_FOREACH (auto const& p, QAudioDeviceInfo::availableDevices (QAudio::AudioInput)) // available audio input devices
{
if (p.deviceName () == saved_name)
{
audio_input_device_ = p;
}
}
}
}
{
//
// retrieve audio output device
//
auto saved_name = settings_->value("SoundOutName").toString();
// deal with special Windows default audio devices
auto default_device = QAudioDeviceInfo::defaultOutputDevice ();
if (saved_name == default_device.deviceName ())
{
audio_output_device_ = default_device;
default_audio_output_device_selected_ = true;
}
else
{
default_audio_output_device_selected_ = false;
Q_FOREACH (auto const& p, QAudioDeviceInfo::availableDevices (QAudio::AudioOutput)) // available audio output devices
{
if (p.deviceName () == saved_name)
{
audio_output_device_ = p;
}
}
}
}
// retrieve audio channel info
audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ());
audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ());
type_2_msg_gen_ = settings_->value ("Type2MsgGen", QVariant::fromValue (Configuration::type_2_msg_3_full)).value<Configuration::Type2MsgGen> (); type_2_msg_gen_ = settings_->value ("Type2MsgGen", QVariant::fromValue (Configuration::type_2_msg_3_full)).value<Configuration::Type2MsgGen> ();
@ -1547,6 +1516,27 @@ void Configuration::impl::read_settings ()
pwrBandTuneMemory_ = settings_->value("pwrBandTuneMemory",false).toBool (); pwrBandTuneMemory_ = settings_->value("pwrBandTuneMemory",false).toBool ();
} }
void Configuration::impl::find_audio_devices ()
{
//
// retrieve audio input device
//
auto saved_name = settings_->value ("SoundInName").toString ();
audio_input_device_ = find_audio_device (QAudio::AudioInput, ui_->sound_input_combo_box, saved_name);
audio_input_channel_ = AudioDevice::fromString (settings_->value ("AudioInputChannel", "Mono").toString ());
update_audio_channels (ui_->sound_input_combo_box, ui_->sound_input_combo_box->currentIndex (), ui_->sound_input_channel_combo_box, false);
ui_->sound_input_channel_combo_box->setCurrentIndex (audio_input_channel_);
//
// retrieve audio output device
//
saved_name = settings_->value("SoundOutName").toString();
audio_output_channel_ = AudioDevice::fromString (settings_->value ("AudioOutputChannel", "Mono").toString ());
audio_output_device_ = find_audio_device (QAudio::AudioOutput, ui_->sound_output_combo_box, saved_name);
update_audio_channels (ui_->sound_output_combo_box, ui_->sound_output_combo_box->currentIndex (), ui_->sound_output_channel_combo_box, true);
ui_->sound_output_channel_combo_box->setCurrentIndex (audio_output_channel_);
}
void Configuration::impl::write_settings () void Configuration::impl::write_settings ()
{ {
SettingsGroup g {settings_, "Configuration"}; SettingsGroup g {settings_, "Configuration"};
@ -1566,25 +1556,8 @@ void Configuration::impl::write_settings ()
settings_->setValue ("PTTport", rig_params_.ptt_port); settings_->setValue ("PTTport", rig_params_.ptt_port);
settings_->setValue ("SaveDir", save_directory_.absolutePath ()); settings_->setValue ("SaveDir", save_directory_.absolutePath ());
settings_->setValue ("AzElDir", azel_directory_.absolutePath ()); settings_->setValue ("AzElDir", azel_directory_.absolutePath ());
if (default_audio_input_device_selected_)
{
settings_->setValue ("SoundInName", QAudioDeviceInfo::defaultInputDevice ().deviceName ());
}
else
{
settings_->setValue ("SoundInName", audio_input_device_.deviceName ()); settings_->setValue ("SoundInName", audio_input_device_.deviceName ());
}
if (default_audio_output_device_selected_)
{
settings_->setValue ("SoundOutName", QAudioDeviceInfo::defaultOutputDevice ().deviceName ());
}
else
{
settings_->setValue ("SoundOutName", audio_output_device_.deviceName ()); settings_->setValue ("SoundOutName", audio_output_device_.deviceName ());
}
settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_)); settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_));
settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_)); settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_));
settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_)); settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_));
@ -1658,6 +1631,7 @@ void Configuration::impl::write_settings ()
settings_->setValue ("pwrBandTuneMemory", pwrBandTuneMemory_); settings_->setValue ("pwrBandTuneMemory", pwrBandTuneMemory_);
settings_->setValue ("Region", QVariant::fromValue (region_)); settings_->setValue ("Region", QVariant::fromValue (region_));
settings_->setValue ("AutoGrid", use_dynamic_grid_); settings_->setValue ("AutoGrid", use_dynamic_grid_);
settings_->sync ();
} }
void Configuration::impl::set_rig_invariants () void Configuration::impl::set_rig_invariants ()
@ -1790,17 +1764,27 @@ void Configuration::impl::set_rig_invariants ()
bool Configuration::impl::validate () bool Configuration::impl::validate ()
{ {
if (ui_->sound_input_combo_box->currentIndex () < 0 if (ui_->sound_input_combo_box->currentIndex () < 0
&& !QAudioDeviceInfo::availableDevices (QAudio::AudioInput).empty ()) && audio_input_device_.isNull ())
{ {
find_tab (ui_->sound_input_combo_box);
MessageBox::critical_message (this, tr ("Invalid audio input device"));
return false;
}
if (ui_->sound_input_channel_combo_box->currentIndex () < 0
&& audio_input_device_.isNull ())
{
find_tab (ui_->sound_input_combo_box);
MessageBox::critical_message (this, tr ("Invalid audio input device")); MessageBox::critical_message (this, tr ("Invalid audio input device"));
return false; return false;
} }
if (ui_->sound_output_combo_box->currentIndex () < 0 if (ui_->sound_output_combo_box->currentIndex () < 0
&& !QAudioDeviceInfo::availableDevices (QAudio::AudioOutput).empty ()) && audio_output_device_.isNull ())
{ {
MessageBox::critical_message (this, tr ("Invalid audio out device")); find_tab (ui_->sound_output_combo_box);
return false; MessageBox::information_message (this, tr ("Invalid audio output device"));
// don't reject as we can work without an audio output
} }
if (!ui_->PTT_method_button_group->checkedButton ()->isEnabled ()) if (!ui_->PTT_method_button_group->checkedButton ()->isEnabled ())
@ -1822,16 +1806,7 @@ bool Configuration::impl::validate ()
if (ui_->rbField_Day->isEnabled () && ui_->rbField_Day->isChecked () && if (ui_->rbField_Day->isEnabled () && ui_->rbField_Day->isChecked () &&
!ui_->Field_Day_Exchange->hasAcceptableInput ()) !ui_->Field_Day_Exchange->hasAcceptableInput ())
{ {
for (auto * parent = ui_->Field_Day_Exchange->parentWidget (); parent; parent = parent->parentWidget ()) find_tab (ui_->Field_Day_Exchange);
{
auto index = ui_->configuration_tabs->indexOf (parent);
if (index != -1)
{
ui_->configuration_tabs->setCurrentIndex (index);
break;
}
}
ui_->Field_Day_Exchange->setFocus ();
MessageBox::critical_message (this, tr ("Invalid Contest Exchange") MessageBox::critical_message (this, tr ("Invalid Contest Exchange")
, tr ("You must input a valid ARRL Field Day exchange")); , tr ("You must input a valid ARRL Field Day exchange"));
return false; return false;
@ -1840,16 +1815,7 @@ bool Configuration::impl::validate ()
if (ui_->rbRTTY_Roundup->isEnabled () && ui_->rbRTTY_Roundup->isChecked () && if (ui_->rbRTTY_Roundup->isEnabled () && ui_->rbRTTY_Roundup->isChecked () &&
!ui_->RTTY_Exchange->hasAcceptableInput ()) !ui_->RTTY_Exchange->hasAcceptableInput ())
{ {
for (auto * parent = ui_->RTTY_Exchange->parentWidget (); parent; parent = parent->parentWidget ()) find_tab (ui_->RTTY_Exchange);
{
auto index = ui_->configuration_tabs->indexOf (parent);
if (index != -1)
{
ui_->configuration_tabs->setCurrentIndex (index);
break;
}
}
ui_->RTTY_Exchange->setFocus ();
MessageBox::critical_message (this, tr ("Invalid Contest Exchange") MessageBox::critical_message (this, tr ("Invalid Contest Exchange")
, tr ("You must input a valid ARRL RTTY Roundup exchange")); , tr ("You must input a valid ARRL RTTY Roundup exchange"));
return false; return false;
@ -1970,59 +1936,19 @@ void Configuration::impl::accept ()
// Check to see whether SoundInThread must be restarted, // Check to see whether SoundInThread must be restarted,
// and save user parameters. // and save user parameters.
{ {
auto const& device_name = ui_->sound_input_combo_box->currentText (); auto const& selected_device = ui_->sound_input_combo_box->currentData ().value<audio_info_type> ().first;
if (device_name != audio_input_device_.deviceName ()) if (selected_device != audio_input_device_)
{ {
auto const& default_device = QAudioDeviceInfo::defaultInputDevice (); audio_input_device_ = selected_device;
if (device_name == default_device.deviceName ())
{
audio_input_device_ = default_device;
}
else
{
bool found {false};
Q_FOREACH (auto const& d, QAudioDeviceInfo::availableDevices (QAudio::AudioInput))
{
if (device_name == d.deviceName ())
{
audio_input_device_ = d;
found = true;
}
}
if (!found)
{
audio_input_device_ = default_device;
}
}
restart_sound_input_device_ = true; restart_sound_input_device_ = true;
} }
} }
{ {
auto const& device_name = ui_->sound_output_combo_box->currentText (); auto const& selected_device = ui_->sound_output_combo_box->currentData ().value<audio_info_type> ().first;
if (device_name != audio_output_device_.deviceName ()) if (selected_device != audio_output_device_)
{ {
auto const& default_device = QAudioDeviceInfo::defaultOutputDevice (); audio_output_device_ = selected_device;
if (device_name == default_device.deviceName ())
{
audio_output_device_ = default_device;
}
else
{
bool found {false};
Q_FOREACH (auto const& d, QAudioDeviceInfo::availableDevices (QAudio::AudioOutput))
{
if (device_name == d.deviceName ())
{
audio_output_device_ = d;
found = true;
}
}
if (!found)
{
audio_output_device_ = default_device;
}
}
restart_sound_output_device_ = true; restart_sound_output_device_ = true;
} }
} }
@ -2306,16 +2232,6 @@ void Configuration::impl::on_PTT_method_button_group_buttonClicked (int /* id */
set_rig_invariants (); set_rig_invariants ();
} }
void Configuration::impl::on_sound_input_combo_box_currentTextChanged (QString const& text)
{
default_audio_input_device_selected_ = QAudioDeviceInfo::defaultInputDevice ().deviceName () == text;
}
void Configuration::impl::on_sound_output_combo_box_currentTextChanged (QString const& text)
{
default_audio_output_device_selected_ = QAudioDeviceInfo::defaultOutputDevice ().deviceName () == text;
}
void Configuration::impl::on_add_macro_line_edit_editingFinished () void Configuration::impl::on_add_macro_line_edit_editingFinished ()
{ {
ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ()); ui_->add_macro_line_edit->setText (ui_->add_macro_line_edit->text ().toUpper ());
@ -2694,6 +2610,7 @@ void Configuration::impl::transceiver_frequency (Frequency f)
current_offset_ = stations_.offset (f); current_offset_ = stations_.offset (f);
cached_rig_state_.frequency (apply_calibration (f + current_offset_)); cached_rig_state_.frequency (apply_calibration (f + current_offset_));
qDebug () << "Configuration::impl::transceiver_frequency: n:" << transceiver_command_number_ + 1 << "f:" << f;
Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_); Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_);
} }
@ -2719,6 +2636,7 @@ void Configuration::impl::transceiver_tx_frequency (Frequency f)
cached_rig_state_.tx_frequency (apply_calibration (f + current_tx_offset_)); cached_rig_state_.tx_frequency (apply_calibration (f + current_tx_offset_));
} }
qDebug () << "Configuration::impl::transceiver_tx_frequency: n:" << transceiver_command_number_ + 1 << "f:" << f;
Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_); Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_);
} }
} }
@ -2727,6 +2645,7 @@ void Configuration::impl::transceiver_mode (MODE m)
{ {
cached_rig_state_.online (true); // we want the rig online cached_rig_state_.online (true); // we want the rig online
cached_rig_state_.mode (m); cached_rig_state_.mode (m);
qDebug () << "Configuration::impl::transceiver_mode: n:" << transceiver_command_number_ + 1 << "m:" << m;
Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_); Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_);
} }
@ -2735,6 +2654,7 @@ void Configuration::impl::transceiver_ptt (bool on)
cached_rig_state_.online (true); // we want the rig online cached_rig_state_.online (true); // we want the rig online
set_cached_mode (); set_cached_mode ();
cached_rig_state_.ptt (on); cached_rig_state_.ptt (on);
qDebug () << "Configuration::impl::transceiver_ptt: n:" << transceiver_command_number_ + 1 << "on:" << on;
Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_); Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_);
} }
@ -2833,45 +2753,20 @@ void Configuration::impl::close_rig ()
} }
} }
// load the available audio devices into the selection combo box and // find the audio device that matches the specified name, also
// select the default device if the current device isn't set or isn't // populate into the selection combo box with any devices we find in
// available // the search
bool Configuration::impl::load_audio_devices (QAudio::Mode mode, QComboBox * combo_box, QAudioDeviceInfo * device) QAudioDeviceInfo Configuration::impl::find_audio_device (QAudio::Mode mode, QComboBox * combo_box
, QString const& device_name)
{ {
using std::copy; using std::copy;
using std::back_inserter; using std::back_inserter;
bool result {false};
combo_box->clear (); combo_box->clear ();
int current_index = -1; int current_index = -1;
int default_index = -1; auto const& devices = QAudioDeviceInfo::availableDevices (mode);
Q_FOREACH (auto const& p, devices)
int extra_items {0};
auto const& default_device = (mode == QAudio::AudioInput ? QAudioDeviceInfo::defaultInputDevice () : QAudioDeviceInfo::defaultOutputDevice ());
// deal with special default audio devices on Windows
if ("Default Input Device" == default_device.deviceName ()
|| "Default Output Device" == default_device.deviceName ())
{
default_index = 0;
QList<QVariant> channel_counts;
auto scc = default_device.supportedChannelCounts ();
copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts));
combo_box->addItem (default_device.deviceName (), channel_counts);
++extra_items;
if (default_device == *device)
{
current_index = 0;
result = true;
}
}
Q_FOREACH (auto const& p, QAudioDeviceInfo::availableDevices (mode))
{ {
// qDebug () << "Audio device: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes (); // qDebug () << "Audio device: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes ();
@ -2880,25 +2775,45 @@ bool Configuration::impl::load_audio_devices (QAudio::Mode mode, QComboBox * com
auto scc = p.supportedChannelCounts (); auto scc = p.supportedChannelCounts ();
copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts)); copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts));
combo_box->addItem (p.deviceName (), channel_counts); combo_box->addItem (p.deviceName (), QVariant::fromValue (audio_info_type {p, channel_counts}));
if (p.deviceName () == device_name)
{
current_index = combo_box->count () - 1;
combo_box->setCurrentIndex (current_index);
return p;
}
}
combo_box->setCurrentIndex (current_index);
return {};
}
// load the available audio devices into the selection combo box
void Configuration::impl::load_audio_devices (QAudio::Mode mode, QComboBox * combo_box
, QAudioDeviceInfo * device)
{
using std::copy;
using std::back_inserter;
combo_box->clear ();
int current_index = -1;
auto const& devices = QAudioDeviceInfo::availableDevices (mode);
Q_FOREACH (auto const& p, devices)
{
// qDebug () << "Audio device: input:" << (QAudio::AudioInput == mode) << "name:" << p.deviceName () << "preferred format:" << p.preferredFormat () << "endians:" << p.supportedByteOrders () << "codecs:" << p.supportedCodecs () << "channels:" << p.supportedChannelCounts () << "rates:" << p.supportedSampleRates () << "sizes:" << p.supportedSampleSizes () << "types:" << p.supportedSampleTypes ();
// convert supported channel counts into something we can store in the item model
QList<QVariant> channel_counts;
auto scc = p.supportedChannelCounts ();
copy (scc.cbegin (), scc.cend (), back_inserter (channel_counts));
combo_box->addItem (p.deviceName (), QVariant::fromValue (audio_info_type {p, channel_counts}));
if (p == *device) if (p == *device)
{ {
current_index = combo_box->count () - 1; current_index = combo_box->count () - 1;
} }
else if (p == default_device)
{
default_index = combo_box->count () - 1;
}
}
if (current_index < 0) // not found - use default
{
*device = default_device;
result = true;
current_index = default_index;
} }
combo_box->setCurrentIndex (current_index); combo_box->setCurrentIndex (current_index);
return result;
} }
// enable only the channels that are supported by the selected audio device // enable only the channels that are supported by the selected audio device
@ -2910,7 +2825,8 @@ void Configuration::impl::update_audio_channels (QComboBox const * source_combo_
combo_box->setItemData (i, combo_box_item_disabled, Qt::UserRole - 1); combo_box->setItemData (i, combo_box_item_disabled, Qt::UserRole - 1);
} }
Q_FOREACH (QVariant const& v, source_combo_box->itemData (index).toList ()) Q_FOREACH (QVariant const& v
, (source_combo_box->itemData (index).value<audio_info_type> ().second))
{ {
// enable valid options // enable valid options
int n {v.toInt ()}; int n {v.toInt ()};
@ -2930,6 +2846,20 @@ void Configuration::impl::update_audio_channels (QComboBox const * source_combo_
} }
} }
void Configuration::impl::find_tab (QWidget * target)
{
for (auto * parent = target->parentWidget (); parent; parent = parent->parentWidget ())
{
auto index = ui_->configuration_tabs->indexOf (parent);
if (index != -1)
{
ui_->configuration_tabs->setCurrentIndex (index);
break;
}
}
target->setFocus ();
}
// load all the supported rig names into the selection combo box // load all the supported rig names into the selection combo box
void Configuration::impl::enumerate_rigs () void Configuration::impl::enumerate_rigs ()
{ {

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>559</width> <width>554</width>
<height>553</height> <height>557</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -1349,33 +1349,13 @@ radio interface behave as expected.</string>
<string>Soundcard</string> <string>Soundcard</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_6"> <layout class="QGridLayout" name="gridLayout_6">
<item row="1" column="1"> <item row="1" column="0">
<widget class="QComboBox" name="sound_output_combo_box"> <widget class="QLabel" name="sound_output_label">
<property name="sizePolicy"> <property name="text">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed"> <string>Ou&amp;tput:</string>
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property> </property>
<property name="toolTip"> <property name="buddy">
<string>Select the audio CODEC to use for transmitting. <cstring>sound_output_combo_box</cstring>
If this is your default device for system sounds then
ensure that all system sounds are disabled otherwise
you will broadcast any systems sounds generated during
transmitting periods.</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="sound_input_combo_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Select the audio CODEC to use for receiving.</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -1389,33 +1369,6 @@ transmitting periods.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="2">
<widget class="QComboBox" name="sound_input_channel_combo_box">
<property name="toolTip">
<string>Select the channel to use for receiving.</string>
</property>
<item>
<property name="text">
<string>Mono</string>
</property>
</item>
<item>
<property name="text">
<string>Left</string>
</property>
</item>
<item>
<property name="text">
<string>Right</string>
</property>
</item>
<item>
<property name="text">
<string>Both</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2"> <item row="1" column="2">
<widget class="QComboBox" name="sound_output_channel_combo_box"> <widget class="QComboBox" name="sound_output_channel_combo_box">
<property name="toolTip"> <property name="toolTip">
@ -1446,14 +1399,61 @@ both here.</string>
</item> </item>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="0" column="1">
<widget class="QLabel" name="sound_output_label"> <widget class="QComboBox" name="sound_input_combo_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Select the audio CODEC to use for receiving.</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="sound_output_combo_box">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>Select the audio CODEC to use for transmitting.
If this is your default device for system sounds then
ensure that all system sounds are disabled otherwise
you will broadcast any systems sounds generated during
transmitting periods.</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="sound_input_channel_combo_box">
<property name="toolTip">
<string>Select the channel to use for receiving.</string>
</property>
<item>
<property name="text"> <property name="text">
<string>Ou&amp;tput:</string> <string>Mono</string>
</property> </property>
<property name="buddy"> </item>
<cstring>sound_output_combo_box</cstring> <item>
<property name="text">
<string>Left</string>
</property> </property>
</item>
<item>
<property name="text">
<string>Right</string>
</property>
</item>
<item>
<property name="text">
<string>Both</string>
</property>
</item>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -1493,7 +1493,8 @@ both here.</string>
<bool>false</bool> <bool>false</bool>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string> <string notr="true">background-color: rgb(255, 255, 255);
color: rgb(0, 0, 0);</string>
</property> </property>
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
@ -1541,7 +1542,8 @@ both here.</string>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string> <string notr="true">background-color: rgb(255, 255, 255);
color: rgb(0, 0, 0);</string>
</property> </property>
<property name="text"> <property name="text">
<string>TextLabel</string> <string>TextLabel</string>
@ -2949,14 +2951,20 @@ Right click for insert and delete options.</string>
<tabstop>use_dynamic_grid</tabstop> <tabstop>use_dynamic_grid</tabstop>
<tabstop>region_combo_box</tabstop> <tabstop>region_combo_box</tabstop>
<tabstop>type_2_msg_gen_combo_box</tabstop> <tabstop>type_2_msg_gen_combo_box</tabstop>
<tabstop>decodes_from_top_check_box</tabstop>
<tabstop>insert_blank_check_box</tabstop>
<tabstop>miles_check_box</tabstop>
<tabstop>TX_messages_check_box</tabstop> <tabstop>TX_messages_check_box</tabstop>
<tabstop>DXCC_check_box</tabstop> <tabstop>DXCC_check_box</tabstop>
<tabstop>ppfx_check_box</tabstop>
<tabstop>font_push_button</tabstop> <tabstop>font_push_button</tabstop>
<tabstop>decoded_text_font_push_button</tabstop> <tabstop>decoded_text_font_push_button</tabstop>
<tabstop>monitor_off_check_box</tabstop> <tabstop>monitor_off_check_box</tabstop>
<tabstop>monitor_last_used_check_box</tabstop> <tabstop>monitor_last_used_check_box</tabstop>
<tabstop>quick_call_check_box</tabstop> <tabstop>quick_call_check_box</tabstop>
<tabstop>disable_TX_on_73_check_box</tabstop> <tabstop>disable_TX_on_73_check_box</tabstop>
<tabstop>force_call_1st_check_box</tabstop>
<tabstop>alternate_bindings_check_box</tabstop>
<tabstop>CW_id_after_73_check_box</tabstop> <tabstop>CW_id_after_73_check_box</tabstop>
<tabstop>enable_VHF_features_check_box</tabstop> <tabstop>enable_VHF_features_check_box</tabstop>
<tabstop>tx_QSY_check_box</tabstop> <tabstop>tx_QSY_check_box</tabstop>
@ -2975,8 +2983,8 @@ Right click for insert and delete options.</string>
<tabstop>CAT_one_stop_bit_radio_button</tabstop> <tabstop>CAT_one_stop_bit_radio_button</tabstop>
<tabstop>CAT_two_stop_bit_radio_button</tabstop> <tabstop>CAT_two_stop_bit_radio_button</tabstop>
<tabstop>CAT_handshake_default_radio_button</tabstop> <tabstop>CAT_handshake_default_radio_button</tabstop>
<tabstop>CAT_handshake_none_radio_button</tabstop>
<tabstop>CAT_handshake_xon_radio_button</tabstop> <tabstop>CAT_handshake_xon_radio_button</tabstop>
<tabstop>CAT_handshake_none_radio_button</tabstop>
<tabstop>CAT_handshake_hardware_radio_button</tabstop> <tabstop>CAT_handshake_hardware_radio_button</tabstop>
<tabstop>force_DTR_combo_box</tabstop> <tabstop>force_DTR_combo_box</tabstop>
<tabstop>force_RTS_combo_box</tabstop> <tabstop>force_RTS_combo_box</tabstop>
@ -3014,6 +3022,7 @@ Right click for insert and delete options.</string>
<tabstop>clear_DX_check_box</tabstop> <tabstop>clear_DX_check_box</tabstop>
<tabstop>opCallEntry</tabstop> <tabstop>opCallEntry</tabstop>
<tabstop>psk_reporter_check_box</tabstop> <tabstop>psk_reporter_check_box</tabstop>
<tabstop>psk_reporter_tcpip_check_box</tabstop>
<tabstop>udp_server_line_edit</tabstop> <tabstop>udp_server_line_edit</tabstop>
<tabstop>udp_server_port_spin_box</tabstop> <tabstop>udp_server_port_spin_box</tabstop>
<tabstop>accept_udp_requests_check_box</tabstop> <tabstop>accept_udp_requests_check_box</tabstop>
@ -3028,9 +3037,13 @@ Right click for insert and delete options.</string>
<tabstop>stations_table_view</tabstop> <tabstop>stations_table_view</tabstop>
<tabstop>highlighting_list_view</tabstop> <tabstop>highlighting_list_view</tabstop>
<tabstop>reset_highlighting_to_defaults_push_button</tabstop> <tabstop>reset_highlighting_to_defaults_push_button</tabstop>
<tabstop>highlight_by_mode_check_box</tabstop>
<tabstop>only_fields_check_box</tabstop>
<tabstop>include_WAE_check_box</tabstop>
<tabstop>rescan_log_push_button</tabstop>
<tabstop>LotW_CSV_URL_line_edit</tabstop> <tabstop>LotW_CSV_URL_line_edit</tabstop>
<tabstop>LotW_CSV_fetch_push_button</tabstop>
<tabstop>LotW_days_since_upload_spin_box</tabstop> <tabstop>LotW_days_since_upload_spin_box</tabstop>
<tabstop>LotW_CSV_fetch_push_button</tabstop>
<tabstop>sbNtrials</tabstop> <tabstop>sbNtrials</tabstop>
<tabstop>sbAggressive</tabstop> <tabstop>sbAggressive</tabstop>
<tabstop>cbTwoPass</tabstop> <tabstop>cbTwoPass</tabstop>
@ -3039,13 +3052,18 @@ Right click for insert and delete options.</string>
<tabstop>sbTxDelay</tabstop> <tabstop>sbTxDelay</tabstop>
<tabstop>cbx2ToneSpacing</tabstop> <tabstop>cbx2ToneSpacing</tabstop>
<tabstop>cbx4ToneSpacing</tabstop> <tabstop>cbx4ToneSpacing</tabstop>
<tabstop>rbLowSidelobes</tabstop>
<tabstop>rbMaxSensitivity</tabstop>
<tabstop>gbSpecialOpActivity</tabstop>
<tabstop>rbFox</tabstop> <tabstop>rbFox</tabstop>
<tabstop>rbHound</tabstop>
<tabstop>rbNA_VHF_Contest</tabstop> <tabstop>rbNA_VHF_Contest</tabstop>
<tabstop>rbEU_VHF_Contest</tabstop>
<tabstop>rbField_Day</tabstop> <tabstop>rbField_Day</tabstop>
<tabstop>Field_Day_Exchange</tabstop> <tabstop>Field_Day_Exchange</tabstop>
<tabstop>rbEU_VHF_Contest</tabstop>
<tabstop>rbRTTY_Roundup</tabstop> <tabstop>rbRTTY_Roundup</tabstop>
<tabstop>RTTY_Exchange</tabstop> <tabstop>RTTY_Exchange</tabstop>
<tabstop>rbWW_DIGI</tabstop>
</tabstops> </tabstops>
<resources/> <resources/>
<connections> <connections>
@ -3116,12 +3134,12 @@ Right click for insert and delete options.</string>
</connections> </connections>
<buttongroups> <buttongroups>
<buttongroup name="PTT_method_button_group"/> <buttongroup name="PTT_method_button_group"/>
<buttongroup name="TX_mode_button_group"/> <buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="CAT_handshake_button_group"/> <buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="TX_audio_source_button_group"/> <buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="special_op_activity_button_group"/> <buttongroup name="special_op_activity_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/> <buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
</buttongroups> </buttongroups>
</ui> </ui>

View File

@ -56,6 +56,7 @@ void Detector::clear ()
qint64 Detector::writeData (char const * data, qint64 maxSize) qint64 Detector::writeData (char const * data, qint64 maxSize)
{ {
//qDebug () << "Detector::writeData: size:" << maxSize;
static unsigned mstr0=999999; static unsigned mstr0=999999;
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time
@ -119,8 +120,7 @@ qint64 Detector::writeData (char const * data, qint64 maxSize)
remaining -= numFramesProcessed; remaining -= numFramesProcessed;
} }
// we drop any data past the end of the buffer on the floor until
// the next period starts
return maxSize; // we drop any data past the end of the buffer on return maxSize;
// the floor until the next period starts
} }

View File

@ -105,7 +105,14 @@ void Modulator::start (QString mode, unsigned symbolsLength, double framesPerSym
// qDebug() << "delay_ms:" << delay_ms << "mstr:" << mstr << "m_silentFrames:" << m_silentFrames << "m_ic:" << m_ic << "m_state:" << m_state; // qDebug() << "delay_ms:" << delay_ms << "mstr:" << mstr << "m_silentFrames:" << m_silentFrames << "m_ic:" << m_ic << "m_state:" << m_state;
m_stream = stream; m_stream = stream;
if (m_stream) m_stream->restart (this); if (m_stream)
{
m_stream->restart (this);
}
else
{
qDebug () << "Modulator::start: no audio output stream assigned";
}
} }
void Modulator::tune (bool newState) void Modulator::tune (bool newState)

View File

@ -465,7 +465,11 @@ void MessageClient::set_server (QString const& server)
{ {
// queue a host address lookup // queue a host address lookup
TRACE_UDP ("server host DNS lookup:" << server); TRACE_UDP ("server host DNS lookup:" << server);
#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
m_->dns_lookup_id_ = QHostInfo::lookupHost (server, &*m_, &MessageClient::impl::host_info_results); m_->dns_lookup_id_ = QHostInfo::lookupHost (server, &*m_, &MessageClient::impl::host_info_results);
#else
m_->dns_lookup_id_ = QHostInfo::lookupHost (server, &*m_, SLOT (host_info_results (QHostInfo)));
#endif
} }
} }

View File

@ -65,7 +65,6 @@ public:
// This timer sets the interval to check for spots to send. // This timer sets the interval to check for spots to send.
connect (&report_timer_, &QTimer::timeout, [this] () {send_report ();}); connect (&report_timer_, &QTimer::timeout, [this] () {send_report ();});
report_timer_.start (MIN_SEND_INTERVAL * 1000);
// This timer repeats the sending of IPFIX templates and receiver // This timer repeats the sending of IPFIX templates and receiver
// information if we are using UDP, in case server has been // information if we are using UDP, in case server has been
@ -80,7 +79,6 @@ public:
send_receiver_data_ = 3; // three times send_receiver_data_ = 3; // three times
} }
}); });
descriptor_timer_.start (1 * 60 * 60 * 1000); // hourly
} }
void check_connection () void check_connection ()
@ -156,6 +154,25 @@ public:
// use this for pseudo connection with UDP, allows us to use // use this for pseudo connection with UDP, allows us to use
// QIODevice::write() instead of QUDPSocket::writeDatagram() // QIODevice::write() instead of QUDPSocket::writeDatagram()
socket_->connectToHost (HOST, SERVICE_PORT, QAbstractSocket::WriteOnly); socket_->connectToHost (HOST, SERVICE_PORT, QAbstractSocket::WriteOnly);
if (!report_timer_.isActive ())
{
report_timer_.start (MIN_SEND_INTERVAL * 1000);
}
if (!descriptor_timer_.isActive ())
{
descriptor_timer_.start (1 * 60 * 60 * 1000); // hourly
}
}
void stop ()
{
if (socket_)
{
socket_->disconnectFromHost ();
}
descriptor_timer_.stop ();
report_timer_.stop ();
} }
void send_report (bool send_residue = false); void send_report (bool send_residue = false);
@ -402,7 +419,13 @@ void PSKReporter::impl::send_report (bool send_residue)
writeUtfString (tx_out, spot.grid_); writeUtfString (tx_out, spot.grid_);
tx_out tx_out
<< quint8 (1u) // REPORTER_SOURCE_AUTOMATIC << quint8 (1u) // REPORTER_SOURCE_AUTOMATIC
<< static_cast<quint32> (spot.time_.toSecsSinceEpoch ()); << static_cast<quint32> (
#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
spot.time_.toSecsSinceEpoch ()
#else
spot.time_.toMSecsSinceEpoch () / 1000
#endif
);
} }
auto len = payload_.size () + tx_data_.size (); auto len = payload_.size () + tx_data_.size ();
@ -429,7 +452,13 @@ void PSKReporter::impl::send_report (bool send_residue)
// insert Length and Export Time // insert Length and Export Time
set_length (message, payload_); set_length (message, payload_);
message.device ()->seek (2 * sizeof (quint16)); message.device ()->seek (2 * sizeof (quint16));
message << static_cast<quint32> (QDateTime::currentDateTime ().toSecsSinceEpoch ()); message << static_cast<quint32> (
#if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)
QDateTime::currentDateTime ().toSecsSinceEpoch ()
#else
QDateTime::currentDateTime ().toMSecsSinceEpoch () / 1000
#endif
);
// Send data to PSK Reporter site // Send data to PSK Reporter site
socket_->write (payload_); // TODO: handle errors socket_->write (payload_); // TODO: handle errors
@ -465,6 +494,7 @@ void PSKReporter::reconnect ()
void PSKReporter::setLocalStation (QString const& call, QString const& gridSquare, QString const& antenna) void PSKReporter::setLocalStation (QString const& call, QString const& gridSquare, QString const& antenna)
{ {
m_->check_connection ();
if (call != m_->rx_call_ || gridSquare != m_->rx_grid_ || antenna != m_->rx_ant_) if (call != m_->rx_call_ || gridSquare != m_->rx_grid_ || antenna != m_->rx_ant_)
{ {
m_->send_receiver_data_ = m_->socket_ m_->send_receiver_data_ = m_->socket_
@ -478,6 +508,7 @@ void PSKReporter::setLocalStation (QString const& call, QString const& gridSquar
bool PSKReporter::addRemoteStation (QString const& call, QString const& grid, Radio::Frequency freq bool PSKReporter::addRemoteStation (QString const& call, QString const& grid, Radio::Frequency freq
, QString const& mode, int snr) , QString const& mode, int snr)
{ {
m_->check_connection ();
if (m_->socket_ && m_->socket_->isValid ()) if (m_->socket_ && m_->socket_->isValid ())
{ {
if (QAbstractSocket::UnconnectedState == m_->socket_->state ()) if (QAbstractSocket::UnconnectedState == m_->socket_->state ())
@ -490,7 +521,14 @@ bool PSKReporter::addRemoteStation (QString const& call, QString const& grid, Ra
return false; return false;
} }
void PSKReporter::sendReport () void PSKReporter::sendReport (bool last)
{
if (m_->socket_ && QAbstractSocket::ConnectedState == m_->socket_->state ())
{ {
m_->send_report (true); m_->send_report (true);
} }
if (last)
{
m_->stop ();
}
}

View File

@ -29,7 +29,7 @@ public:
// //
// Flush any pending spots to PSK Reporter // Flush any pending spots to PSK Reporter
// //
void sendReport (); void sendReport (bool last = false);
Q_SIGNAL void errorOccurred (QString const& reason); Q_SIGNAL void errorOccurred (QString const& reason);

View File

@ -220,7 +220,7 @@ public:
, carry_ {false} , carry_ {false}
, seed_ {{rand (), rand (), rand (), rand (), rand (), rand (), rand (), rand ()}} , seed_ {{rand (), rand (), rand (), rand (), rand (), rand (), rand (), rand ()}}
, gen_ {seed_} , gen_ {seed_}
, dist_ {1, 100} , dist_ {0, 99}
{ {
auto num_bands = configuration_->bands ()->rowCount (); auto num_bands = configuration_->bands ()->rowCount ();
for (auto& flags : bands_) for (auto& flags : bands_)

1609
cty.dat

File diff suppressed because it is too large Load Diff

View File

@ -319,12 +319,12 @@ AD1CCty::AD1CCty (Configuration const * configuration)
{ {
Q_ASSERT (configuration); Q_ASSERT (configuration);
// TODO: G4WJS - consider doing the following asynchronously to // TODO: G4WJS - consider doing the following asynchronously to
// speed up startup. Not urgent as it takes less than 1s on a Core // speed up startup. Not urgent as it takes less than 0.5s on a Core
// i7 reading BIG CTY.DAT. // i7 reading BIG CTY.DAT.
QDir dataPath {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}; QDir dataPath {QStandardPaths::writableLocation (QStandardPaths::DataLocation)};
m_->path_ = dataPath.exists (file_name) m_->path_ = dataPath.exists (file_name)
? dataPath.absoluteFilePath (file_name) // user override ? dataPath.absoluteFilePath (file_name) // user override
: QString {":/"} + file_name; // or original in the resources FS : configuration->data_dir ().absoluteFilePath (file_name); // or original
QFile file {m_->path_}; QFile file {m_->path_};
if (file.open (QFile::ReadOnly)) if (file.open (QFile::ReadOnly))
{ {

View File

@ -15,14 +15,14 @@ namespace
Radio::Frequency lower_bound_; Radio::Frequency lower_bound_;
Radio::Frequency upper_bound_; Radio::Frequency upper_bound_;
} constexpr ADIF_bands[] = { } constexpr ADIF_bands[] = {
{"2190m", 136000u, 137000u}, {"2190m", 135700u, 137800u},
{"630m", 472000u, 479000u}, {"630m", 472000u, 479000u},
{"560m", 501000u, 504000u}, {"560m", 501000u, 504000u},
{"160m", 1800000u, 2000000u}, {"160m", 1800000u, 2000000u},
{"80m", 3500000u, 4000000u}, {"80m", 3500000u, 4000000u},
{"60m", 5060000u, 5450000u}, {"60m", 5060000u, 5450000u},
{"40m", 7000000u, 7300000u}, {"40m", 7000000u, 7300000u},
{"30m", 10000000u, 10150000u}, {"30m", 10100000u, 10150000u},
{"20m", 14000000u, 14350000u}, {"20m", 14000000u, 14350000u},
{"17m", 18068000u, 18168000u}, {"17m", 18068000u, 18168000u},
{"15m", 21000000u, 21450000u}, {"15m", 21000000u, 21450000u},

View File

@ -37,14 +37,14 @@ void update_dynamic_property (QWidget * widget, char const * property, QVariant
widget->update (); widget->update ();
} }
QDateTime qt_round_date_time_to (QDateTime dt, int seconds) QDateTime qt_round_date_time_to (QDateTime dt, int milliseconds)
{ {
dt.setSecsSinceEpoch (dt.addSecs (seconds - 1).toSecsSinceEpoch () / seconds * seconds); dt.setMSecsSinceEpoch (dt.addMSecs (milliseconds / 2).toMSecsSinceEpoch () / milliseconds * milliseconds);
return dt; return dt;
} }
QDateTime qt_truncate_date_time_to (QDateTime dt, int seconds) QDateTime qt_truncate_date_time_to (QDateTime dt, int milliseconds)
{ {
dt.setSecsSinceEpoch (dt.toSecsSinceEpoch () / seconds * seconds); dt.setMSecsSinceEpoch (dt.toMSecsSinceEpoch () / milliseconds * milliseconds);
return dt; return dt;
} }

View File

@ -69,11 +69,11 @@ QString font_as_stylesheet (QFont const&);
// conditional style sheet updates // conditional style sheet updates
void update_dynamic_property (QWidget *, char const * property, QVariant const& value); void update_dynamic_property (QWidget *, char const * property, QVariant const& value);
// round a QDateTime instance to an interval // round a QDateTime instance to an integral interval of milliseconds
QDateTime qt_round_date_time_to (QDateTime dt, int seconds); QDateTime qt_round_date_time_to (QDateTime dt, int milliseconds);
// truncate a QDateTime to an interval // truncate a QDateTime to an integral interval of milliseconds
QDateTime qt_truncate_date_time_to (QDateTime dt, int seconds); QDateTime qt_truncate_date_time_to (QDateTime dt, int milliseconds);
template <class T> template <class T>
class VPtr class VPtr

23
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,23 @@
find_package (Qt5Test 5 REQUIRED)
#
# Compiler options
#
set (CMAKE_CXX_STANDARD 11)
add_compile_options ("$<$<COMPILE_LANGUAGE:Fortran>:-Wall;-Wno-conversion;-fno-second-underscore;-fno-f2c>")
add_compile_options ("$<$<AND:$<COMPILE_LANGUAGE:Fortran>,$<CONFIG:Debug>>:-fbounds-check>")
add_compile_options ("$<$<AND:$<COMPILE_LANGUAGE:Fortran>,$<NOT:$<CONFIG:Debug>>>:-funroll-all-loops>")
add_compile_options ("$<$<AND:$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>,$<OR:$<C_COMPILER_ID:GNU>,$<C_COMPILER_ID:Clang>,$<C_COMPILER_ID:AppleClang>>>:-Wall;-Wextra>")
add_compile_options ("$<$<AND:$<COMPILE_LANGUAGE:CXX>,$<CXX_COMPILER_ID:GNU>>:-Wno-pragmas>")
add_compile_options ("$<$<AND:$<OR:$<C_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:GNU>>,$<NOT:$<CONFIG:Debug>>>:-fdata-sections;-ffunction-sections>")
if (${OPENMP_FOUND} OR APPLE)
add_compile_options ("$<$<AND:$<OR:$<COMPILE_LANGUAGE:C>,$<COMPILE_LANGUAGE:CXX>>,$<C_COMPILER_ID:GNU>>:${OpenMP_C_FLAGS}>")
endif ()
# Tell CMake to run moc when necessary
set (CMAKE_AUTOMOC ON)
include_directories (${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR})
add_executable (test_qt_helpers test_qt_helpers.cpp)
target_link_libraries (test_qt_helpers wsjt_qt Qt5::Test)
add_test (test_qt_helpers test_qt_helpers)

138
tests/test_qt_helpers.cpp Normal file
View File

@ -0,0 +1,138 @@
#include <QtTest>
#include <QDateTime>
#include <QDebug>
#include "qt_helpers.hpp"
class TestQtHelpers
: public QObject
{
Q_OBJECT
public:
private:
Q_SLOT void round_15s_date_time_up ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 500}};
QCOMPARE (qt_round_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 30)));
}
Q_SLOT void truncate_15s_date_time_up ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 500}};
QCOMPARE (qt_truncate_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void round_15s_date_time_down ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 499}};
QCOMPARE (qt_round_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void truncate_15s_date_time_down ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 499}};
QCOMPARE (qt_truncate_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void round_15s_date_time_on ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 15}};
QCOMPARE (qt_round_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void truncate_15s_date_time_on ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 15}};
QCOMPARE (qt_truncate_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void round_15s_date_time_under ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 14, 999}};
QCOMPARE (qt_round_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void truncate_15s_date_time_under ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 14, 999}};
QCOMPARE (qt_truncate_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15)));
}
Q_SLOT void round_15s_date_time_over ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 15, 1}};
QCOMPARE (qt_round_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void truncate_15s_date_time_over ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 15, 1}};
QCOMPARE (qt_truncate_date_time_to (dt, 15000), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void round_7p5s_date_time_up ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 26, 250}};
QCOMPARE (qt_round_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 30)));
}
Q_SLOT void truncate_7p5s_date_time_up ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 26, 250}};
QCOMPARE (qt_truncate_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 22, 500)));
}
Q_SLOT void round_7p5s_date_time_down ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 26, 249}};
QCOMPARE (qt_round_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 22, 500)));
}
Q_SLOT void truncate_7p5s_date_time_down ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 26, 249}};
QCOMPARE (qt_truncate_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 22, 500)));
}
Q_SLOT void round_7p5s_date_time_on ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 500}};
QCOMPARE (qt_round_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 22, 500)));
}
Q_SLOT void truncate_7p5s_date_time_on ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 500}};
QCOMPARE (qt_truncate_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 22, 500)));
}
Q_SLOT void round_7p5s_date_time_under ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 499}};
QCOMPARE (qt_round_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 22, 500)));
}
Q_SLOT void truncate_7p5s_date_time_under ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 499}};
QCOMPARE (qt_truncate_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 15)));
}
Q_SLOT void round_7p5s_date_time_over ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 501}};
QCOMPARE (qt_round_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 22, 500)));
}
Q_SLOT void truncate_7p5s_date_time_over ()
{
QDateTime dt {QDate {2020, 8, 6}, QTime {14, 15, 22, 501}};
QCOMPARE (qt_truncate_date_time_to (dt, 7500), QDateTime (QDate (2020, 8, 6), QTime (14, 15, 22, 500)));
}
};
QTEST_MAIN (TestQtHelpers);
#include "test_qt_helpers.moc"

View File

@ -209,6 +209,8 @@ namespace
QRegularExpression grid_regexp {"\\A(?![Rr]{2}73)[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}\\z"}; QRegularExpression grid_regexp {"\\A(?![Rr]{2}73)[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}\\z"};
auto quint32_max = std::numeric_limits<quint32>::max (); auto quint32_max = std::numeric_limits<quint32>::max ();
constexpr int N_WIDGETS {34}; constexpr int N_WIDGETS {34};
constexpr int rx_chunk_size {3456}; // audio samples at 12000 Hz
constexpr int tx_audio_buffer_size {48000 / 5}; // audio frames at 48000 Hz
bool message_is_73 (int type, QStringList const& msg_parts) bool message_is_73 (int type, QStringList const& msg_parts)
{ {
@ -283,7 +285,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_idleMinutes {0}, m_idleMinutes {0},
m_nSubMode {0}, m_nSubMode {0},
m_nclearave {1}, m_nclearave {1},
m_pctx {0},
m_nseq {0}, m_nseq {0},
m_nWSPRdecodes {0}, m_nWSPRdecodes {0},
m_k0 {9999999}, m_k0 {9999999},
@ -309,7 +310,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_bShMsgs {false}, m_bShMsgs {false},
m_bSWL {false}, m_bSWL {false},
m_uploading {false}, m_uploading {false},
m_txNext {false},
m_grid6 {false}, m_grid6 {false},
m_tuneup {false}, m_tuneup {false},
m_bTxTime {false}, m_bTxTime {false},
@ -394,8 +394,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
}, },
m_sfx {"P", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A"}, m_sfx {"P", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A"},
mem_jt9 {shdmem}, mem_jt9 {shdmem},
m_msAudioOutputBuffered (0u),
m_framesAudioInputBuffered (RX_SAMPLE_RATE / 10),
m_downSampleFactor (downSampleFactor), m_downSampleFactor (downSampleFactor),
m_audioThreadPriority (QThread::HighPriority), m_audioThreadPriority (QThread::HighPriority),
m_bandEdited {false}, m_bandEdited {false},
@ -471,9 +469,23 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
connect (this, &MainWindow::startAudioInputStream, m_soundInput, &SoundInput::start); connect (this, &MainWindow::startAudioInputStream, m_soundInput, &SoundInput::start);
connect (this, &MainWindow::suspendAudioInputStream, m_soundInput, &SoundInput::suspend); connect (this, &MainWindow::suspendAudioInputStream, m_soundInput, &SoundInput::suspend);
connect (this, &MainWindow::resumeAudioInputStream, m_soundInput, &SoundInput::resume); connect (this, &MainWindow::resumeAudioInputStream, m_soundInput, &SoundInput::resume);
connect (this, &MainWindow::reset_audio_input_stream, m_soundInput, &SoundInput::reset);
connect (this, &MainWindow::finished, m_soundInput, &SoundInput::stop); connect (this, &MainWindow::finished, m_soundInput, &SoundInput::stop);
connect(m_soundInput, &SoundInput::error, this, &MainWindow::showSoundInError); connect(m_soundInput, &SoundInput::error, this, &MainWindow::showSoundInError);
// connect(m_soundInput, &SoundInput::status, this, &MainWindow::showStatusMessage); // connect(m_soundInput, &SoundInput::status, this, &MainWindow::showStatusMessage);
connect (m_soundInput, &SoundInput::dropped_frames, this, [this] (qint32 dropped_frames, qint64 usec) {
if (dropped_frames > 48000 / 5) // 1/5 second
{
showStatusMessage (tr ("%1 (%2 sec) audio frames dropped").arg (dropped_frames).arg (usec / 1.e6, 5, 'f', 3));
}
if (dropped_frames > 48000) // 1 second
{
MessageBox::warning_message (this
, tr ("Audio Source")
, tr ("Reduce system load")
, tr ("Excessive dropped samples - %1 (%2 sec) audio frames dropped").arg (dropped_frames).arg (usec / 1.e6, 5, 'f', 3));
}
});
connect (&m_audioThread, &QThread::finished, m_soundInput, &QObject::deleteLater); connect (&m_audioThread, &QThread::finished, m_soundInput, &QObject::deleteLater);
connect (this, &MainWindow::finished, this, &MainWindow::close); connect (this, &MainWindow::finished, this, &MainWindow::close);
@ -937,14 +949,24 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
connect (&m_wav_future_watcher, &QFutureWatcher<void>::finished, this, &MainWindow::diskDat); connect (&m_wav_future_watcher, &QFutureWatcher<void>::finished, this, &MainWindow::diskDat);
connect(&watcher3, SIGNAL(finished()),this,SLOT(fast_decode_done())); connect(&watcher3, SIGNAL(finished()),this,SLOT(fast_decode_done()));
Q_EMIT startAudioInputStream (m_config.audio_input_device (), m_framesAudioInputBuffered, m_detector, m_downSampleFactor, m_config.audio_input_channel ()); if (!m_config.audio_input_device ().isNull ())
Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered); {
Q_EMIT startAudioInputStream (m_config.audio_input_device ()
, rx_chunk_size * m_downSampleFactor
, m_detector, m_downSampleFactor, m_config.audio_input_channel ());
}
if (!m_config.audio_output_device ().isNull ())
{
Q_EMIT initializeAudioOutputStream (m_config.audio_output_device ()
, AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2
, tx_audio_buffer_size);
}
Q_EMIT transmitFrequency (ui->TxFreqSpinBox->value () - m_XIT); Q_EMIT transmitFrequency (ui->TxFreqSpinBox->value () - m_XIT);
enable_DXCC_entity (m_config.DXCC ()); // sets text window proportions and (re)inits the logbook enable_DXCC_entity (m_config.DXCC ()); // sets text window proportions and (re)inits the logbook
ui->label_9->setStyleSheet("QLabel{background-color: #aabec8}"); ui->label_9->setStyleSheet("QLabel{color: #000000; background-color: #aabec8}");
ui->label_10->setStyleSheet("QLabel{background-color: #aabec8}"); ui->label_10->setStyleSheet("QLabel{color: #000000; background-color: #aabec8}");
// this must be done before initializing the mode as some modes need // this must be done before initializing the mode as some modes need
// to turn off split on the rig e.g. WSPR // to turn off split on the rig e.g. WSPR
@ -972,7 +994,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
} }
m_saveDecoded=ui->actionSave_decoded->isChecked(); m_saveDecoded=ui->actionSave_decoded->isChecked();
m_saveAll=ui->actionSave_all->isChecked(); m_saveAll=ui->actionSave_all->isChecked();
ui->sbTxPercent->setValue(m_pctx);
ui->TxPowerComboBox->setCurrentIndex(int(.3 * m_dBm + .2)); ui->TxPowerComboBox->setCurrentIndex(int(.3 * m_dBm + .2));
ui->cbUploadWSPR_Spots->setChecked(m_uploadWSPRSpots); ui->cbUploadWSPR_Spots->setChecked(m_uploadWSPRSpots);
if((m_ndepth&7)==1) ui->actionQuickDecode->setChecked(true); if((m_ndepth&7)==1) ui->actionQuickDecode->setChecked(true);
@ -995,12 +1016,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
m_isort=-3; m_isort=-3;
m_max_dB=70; m_max_dB=70;
m_CQtype="CQ"; m_CQtype="CQ";
if(m_mode=="WSPR" and m_pctx>0) {
QPalette palette {ui->sbTxPercent->palette ()};
palette.setColor(QPalette::Base,Qt::yellow);
ui->sbTxPercent->setPalette(palette);
}
fixStop(); fixStop();
VHF_features_enabled(m_config.enable_VHF_features()); VHF_features_enabled(m_config.enable_VHF_features());
m_wideGraph->setVHF(m_config.enable_VHF_features()); m_wideGraph->setVHF(m_config.enable_VHF_features());
@ -1144,7 +1159,7 @@ void MainWindow::writeSettings()
m_settings->setValue("GUItab",ui->tabWidget->currentIndex()); m_settings->setValue("GUItab",ui->tabWidget->currentIndex());
m_settings->setValue("OutBufSize",outBufSize); m_settings->setValue("OutBufSize",outBufSize);
m_settings->setValue ("HoldTxFreq", ui->cbHoldTxFreq->isChecked ()); m_settings->setValue ("HoldTxFreq", ui->cbHoldTxFreq->isChecked ());
m_settings->setValue("PctTx",m_pctx); m_settings->setValue("PctTx", ui->sbTxPercent->value ());
m_settings->setValue("dBm",m_dBm); m_settings->setValue("dBm",m_dBm);
m_settings->setValue("RR73",m_send_RR73); m_settings->setValue("RR73",m_send_RR73);
m_settings->setValue ("WSPRPreferType1", ui->WSPR_prefer_type_1_check_box->isChecked ()); m_settings->setValue ("WSPRPreferType1", ui->WSPR_prefer_type_1_check_box->isChecked ());
@ -1235,7 +1250,8 @@ void MainWindow::readSettings()
ui->TxFreqSpinBox->setValue(0); // ensure a change is signaled ui->TxFreqSpinBox->setValue(0); // ensure a change is signaled
ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq",1500).toInt()); ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq",1500).toInt());
m_ndepth=m_settings->value("NDepth",3).toInt(); m_ndepth=m_settings->value("NDepth",3).toInt();
m_pctx=m_settings->value("PctTx",20).toInt(); ui->sbTxPercent->setValue (m_settings->value ("PctTx", 20).toInt ());
on_sbTxPercent_valueChanged (ui->sbTxPercent->value ());
m_dBm=m_settings->value("dBm",37).toInt(); m_dBm=m_settings->value("dBm",37).toInt();
m_send_RR73=m_settings->value("RR73",false).toBool(); m_send_RR73=m_settings->value("RR73",false).toBool();
if(m_send_RR73) { if(m_send_RR73) {
@ -1244,7 +1260,6 @@ void MainWindow::readSettings()
} }
ui->WSPR_prefer_type_1_check_box->setChecked (m_settings->value ("WSPRPreferType1", true).toBool ()); ui->WSPR_prefer_type_1_check_box->setChecked (m_settings->value ("WSPRPreferType1", true).toBool ());
m_uploadWSPRSpots=m_settings->value("UploadSpots",false).toBool(); m_uploadWSPRSpots=m_settings->value("UploadSpots",false).toBool();
if(!m_uploadWSPRSpots) ui->cbUploadWSPR_Spots->setStyleSheet("QCheckBox{background-color: yellow}");
ui->cbNoOwnCall->setChecked(m_settings->value("NoOwnCall",false).toBool()); ui->cbNoOwnCall->setChecked(m_settings->value("NoOwnCall",false).toBool());
ui->band_hopping_group_box->setChecked (m_settings->value ("BandHopping", false).toBool()); ui->band_hopping_group_box->setChecked (m_settings->value ("BandHopping", false).toBool());
// setup initial value of tx attenuator // setup initial value of tx attenuator
@ -1277,8 +1292,6 @@ void MainWindow::readSettings()
// use these initialisation settings to tune the audio o/p buffer // use these initialisation settings to tune the audio o/p buffer
// size and audio thread priority // size and audio thread priority
m_settings->beginGroup ("Tune"); m_settings->beginGroup ("Tune");
m_msAudioOutputBuffered = m_settings->value ("Audio/OutputBufferMs").toInt ();
m_framesAudioInputBuffered = m_settings->value ("Audio/InputBufferFrames", RX_SAMPLE_RATE / 10).toInt ();
m_audioThreadPriority = static_cast<QThread::Priority> (m_settings->value ("Audio/ThreadPriority", QThread::HighPriority).toInt () % 8); m_audioThreadPriority = static_cast<QThread::Priority> (m_settings->value ("Audio/ThreadPriority", QThread::HighPriority).toInt () % 8);
m_settings->endGroup (); m_settings->endGroup ();
@ -1536,6 +1549,10 @@ void MainWindow::dataSink(qint64 frames)
if(m_mode!="WSPR") decode(); //Start decoder if(m_mode!="WSPR") decode(); //Start decoder
if(m_mode=="FT8" and !m_diskData and (m_ihsym==m_earlyDecode or m_ihsym==m_earlyDecode2)) return; if(m_mode=="FT8" and !m_diskData and (m_ihsym==m_earlyDecode or m_ihsym==m_earlyDecode2)) return;
if (!m_diskData)
{
Q_EMIT reset_audio_input_stream (true); // signals dropped samples
}
if(!m_diskData and (m_saveAll or m_saveDecoded or m_mode=="WSPR" or m_mode=="FST4W")) { if(!m_diskData and (m_saveAll or m_saveDecoded or m_mode=="WSPR" or m_mode=="FST4W")) {
//Always save unless "Save None"; may delete later //Always save unless "Save None"; may delete later
if(m_TRperiod < 60) { if(m_TRperiod < 60) {
@ -1614,14 +1631,15 @@ QString MainWindow::save_wave_file (QString const& name, short const * data, int
format.setChannelCount (1); format.setChannelCount (1);
format.setSampleSize (16); format.setSampleSize (16);
format.setSampleType (QAudioFormat::SignedInt); format.setSampleType (QAudioFormat::SignedInt);
auto source = QString {"%1, %2"}.arg (my_callsign).arg (my_grid); auto source = QString {"%1; %2"}.arg (my_callsign).arg (my_grid);
auto comment = QString {"Mode=%1%2, Freq=%3%4"} auto comment = QString {"Mode=%1%2; Freq=%3%4"}
.arg (mode) .arg (mode)
.arg (QString {(mode.contains ('J') && !mode.contains ('+')) || mode.startsWith ("FST4") .arg (QString {(mode.contains ('J') && !mode.contains ('+'))
? QString {", Sub Mode="} + QChar {'A' + sub_mode} || mode.startsWith ("FST4") || mode.startsWith ("QRA")
? QString {"; Sub Mode="} + QString::number (int (samples / 12000)) + QChar {'A' + sub_mode}
: QString {}}) : QString {}})
.arg (Radio::frequency_MHz_string (frequency)) .arg (Radio::frequency_MHz_string (frequency))
.arg (QString {mode!="WSPR" ? QString {", DXCall=%1, DXGrid=%2"} .arg (QString {mode!="WSPR" ? QString {"; DXCall=%1; DXGrid=%2"}
.arg (his_call) .arg (his_call)
.arg (his_grid).toLocal8Bit () : ""}); .arg (his_grid).toLocal8Bit () : ""});
BWFFile::InfoDictionary list_info { BWFFile::InfoDictionary list_info {
@ -1783,6 +1801,7 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog
auto callsign = m_config.my_callsign (); auto callsign = m_config.my_callsign ();
auto my_grid = m_config.my_grid (); auto my_grid = m_config.my_grid ();
SpecOp nContest0=m_config.special_op_id(); SpecOp nContest0=m_config.special_op_id();
auto psk_on = m_config.spot_to_psk_reporter ();
if (QDialog::Accepted == m_config.exec ()) { if (QDialog::Accepted == m_config.exec ()) {
checkMSK144ContestType(); checkMSK144ContestType();
if (m_config.my_callsign () != callsign) { if (m_config.my_callsign () != callsign) {
@ -1796,18 +1815,25 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog
on_dxGridEntry_textChanged (m_hisGrid); // recalculate distances in case of units change on_dxGridEntry_textChanged (m_hisGrid); // recalculate distances in case of units change
enable_DXCC_entity (m_config.DXCC ()); // sets text window proportions and (re)inits the logbook enable_DXCC_entity (m_config.DXCC ()); // sets text window proportions and (re)inits the logbook
if(m_config.spot_to_psk_reporter ()) pskSetLocal (); pskSetLocal ();
// this will close the connection to PSKReporter if it has been
// disabled
if (psk_on && !m_config.spot_to_psk_reporter ())
{
m_psk_Reporter.sendReport (true);
}
if(m_config.restart_audio_input ()) { if(m_config.restart_audio_input ()) {
Q_EMIT startAudioInputStream (m_config.audio_input_device (), Q_EMIT startAudioInputStream (m_config.audio_input_device ()
m_framesAudioInputBuffered, m_detector, m_downSampleFactor, , rx_chunk_size * m_downSampleFactor
m_config.audio_input_channel ()); , m_detector, m_downSampleFactor
, m_config.audio_input_channel ());
} }
if(m_config.restart_audio_output ()) { if(m_config.restart_audio_output ()) {
Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), Q_EMIT initializeAudioOutputStream (m_config.audio_output_device ()
AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, , AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2
m_msAudioOutputBuffered); , tx_audio_buffer_size);
} }
displayDialFrequency (); displayDialFrequency ();
@ -1909,18 +1935,14 @@ void MainWindow::on_autoButton_clicked (bool checked)
m_nclearave=1; m_nclearave=1;
echocom_.nsum=0; echocom_.nsum=0;
} }
if(m_mode=="WSPR" or m_mode=="FST4W") {
QPalette palette {ui->sbTxPercent->palette ()};
if(m_auto or m_pctx==0) {
palette.setColor(QPalette::Base,Qt::white);
} else {
palette.setColor(QPalette::Base,Qt::yellow);
}
ui->sbTxPercent->setPalette(palette);
}
m_tAutoOn=QDateTime::currentMSecsSinceEpoch()/1000; m_tAutoOn=QDateTime::currentMSecsSinceEpoch()/1000;
} }
void MainWindow::on_sbTxPercent_valueChanged (int n)
{
update_dynamic_property (ui->sbTxPercent, "notx", !n);
}
void MainWindow::auto_tx_mode (bool state) void MainWindow::auto_tx_mode (bool state)
{ {
ui->autoButton->setChecked (state); ui->autoButton->setChecked (state);
@ -2279,8 +2301,8 @@ bool MainWindow::eventFilter (QObject * object, QEvent * event)
void MainWindow::createStatusBar() //createStatusBar void MainWindow::createStatusBar() //createStatusBar
{ {
tx_status_label.setAlignment (Qt::AlignHCenter); tx_status_label.setAlignment (Qt::AlignHCenter);
tx_status_label.setMinimumSize (QSize {150, 18}); tx_status_label.setMinimumSize (QSize {100, 18});
tx_status_label.setStyleSheet ("QLabel{background-color: #00ff00}"); tx_status_label.setStyleSheet ("QLabel{color: #000000; background-color: #00ff00}");
tx_status_label.setFrameStyle (QFrame::Panel | QFrame::Sunken); tx_status_label.setFrameStyle (QFrame::Panel | QFrame::Sunken);
statusBar()->addWidget (&tx_status_label); statusBar()->addWidget (&tx_status_label);
@ -2328,37 +2350,37 @@ void MainWindow::setup_status_bar (bool vhf)
mode_label.setText (m_mode); mode_label.setText (m_mode);
} }
if ("ISCAT" == m_mode) { if ("ISCAT" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #ff9933}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff9933}");
} else if ("JT9" == m_mode) { } else if ("JT9" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #ff6ec7}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff6ec7}");
} else if ("JT4" == m_mode) { } else if ("JT4" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #cc99ff}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #cc99ff}");
} else if ("Echo" == m_mode) { } else if ("Echo" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #66ffff}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #66ffff}");
} else if ("JT9+JT65" == m_mode) { } else if ("JT9+JT65" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #ffff66}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ffff66}");
} else if ("JT65" == m_mode) { } else if ("JT65" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #66ff66}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #66ff66}");
} else if ("QRA64" == m_mode) { } else if ("QRA64" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #99ff33}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff33}");
} else if ("MSK144" == m_mode) { } else if ("MSK144" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #ff6666}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff6666}");
} else if ("FT4" == m_mode) { } else if ("FT4" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #ff0099}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff0099}");
} else if ("FT8" == m_mode) { } else if ("FT8" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #ff6699}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff6699}");
} else if ("FST4" == m_mode) { } else if ("FST4" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #99ff66}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff66}");
} else if ("FST4W" == m_mode) { } else if ("FST4W" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #6699ff}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #6699ff}");
} else if ("FreqCal" == m_mode) { } else if ("FreqCal" == m_mode) {
mode_label.setStyleSheet ("QLabel{background-color: #ff9933}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff9933}");
} }
last_tx_label.setText (QString {}); last_tx_label.setText (QString {});
if (m_mode.contains (QRegularExpression {R"(^(Echo|ISCAT))"})) { if (m_mode.contains (QRegularExpression {R"(^(Echo|ISCAT))"})) {
if (band_hopping_label.isVisible ()) statusBar ()->removeWidget (&band_hopping_label); if (band_hopping_label.isVisible ()) statusBar ()->removeWidget (&band_hopping_label);
} else if (m_mode=="WSPR") { } else if (m_mode=="WSPR") {
mode_label.setStyleSheet ("QLabel{background-color: #ff66ff}"); mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff66ff}");
if (!band_hopping_label.isVisible ()) { if (!band_hopping_label.isVisible ()) {
statusBar ()->addWidget (&band_hopping_label); statusBar ()->addWidget (&band_hopping_label);
band_hopping_label.show (); band_hopping_label.show ();
@ -2689,7 +2711,7 @@ void MainWindow::on_actionOpen_triggered() //Open File
m_path=fname; m_path=fname;
int i1=fname.lastIndexOf("/"); int i1=fname.lastIndexOf("/");
QString baseName=fname.mid(i1+1); QString baseName=fname.mid(i1+1);
tx_status_label.setStyleSheet("QLabel{background-color: #99ffff}"); tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #99ffff}");
tx_status_label.setText(" " + baseName + " "); tx_status_label.setText(" " + baseName + " ");
on_stopButton_clicked(); on_stopButton_clicked();
m_diskData=true; m_diskData=true;
@ -2769,7 +2791,7 @@ void MainWindow::on_actionOpen_next_in_directory_triggered() //Open Next
m_path=fname; m_path=fname;
int i1=fname.lastIndexOf("/"); int i1=fname.lastIndexOf("/");
QString baseName=fname.mid(i1+1); QString baseName=fname.mid(i1+1);
tx_status_label.setStyleSheet("QLabel{background-color: #99ffff}"); tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #99ffff}");
tx_status_label.setText(" " + baseName + " "); tx_status_label.setText(" " + baseName + " ");
m_diskData=true; m_diskData=true;
read_wav_file (fname); read_wav_file (fname);
@ -3109,7 +3131,8 @@ void MainWindow::decode() //decode()
//newdat=1 ==> this is new data, must do the big FFT //newdat=1 ==> this is new data, must do the big FFT
//nagain=1 ==> decode only at fQSO +/- Tol //nagain=1 ==> decode only at fQSO +/- Tol
char *to = (char*)mem_jt9->data(); if (auto * to = reinterpret_cast<char *> (mem_jt9->data()))
{
char *from = (char*) dec_data.ipc; char *from = (char*) dec_data.ipc;
int size=sizeof(struct dec_data); int size=sizeof(struct dec_data);
if(dec_data.params.newdat==0) { if(dec_data.params.newdat==0) {
@ -3160,6 +3183,7 @@ void MainWindow::decode() //decode()
decodeBusy(true); decodeBusy(true);
} }
} }
}
void::MainWindow::fast_decode_done() void::MainWindow::fast_decode_done()
{ {
@ -3206,13 +3230,15 @@ void::MainWindow::fast_decode_done()
void MainWindow::to_jt9(qint32 n, qint32 istart, qint32 idone) void MainWindow::to_jt9(qint32 n, qint32 istart, qint32 idone)
{ {
dec_data_t * dd = reinterpret_cast<dec_data_t *> (mem_jt9->data()); if (auto * dd = reinterpret_cast<dec_data_t *> (mem_jt9->data()))
{
mem_jt9->lock (); mem_jt9->lock ();
dd->ipc[0]=n; dd->ipc[0]=n;
if(istart>=0) dd->ipc[1]=istart; if(istart>=0) dd->ipc[1]=istart;
if(idone>=0) dd->ipc[2]=idone; if(idone>=0) dd->ipc[2]=idone;
mem_jt9->unlock (); mem_jt9->unlock ();
} }
}
void MainWindow::decodeDone () void MainWindow::decodeDone ()
{ {
@ -3268,7 +3294,8 @@ void MainWindow::readFromStdout() //readFromStdout
line_read = line_read.left (64); line_read = line_read.left (64);
} }
} }
if(m_mode!="FT8" and m_mode!="FT4") { if (m_mode!="FT8" and m_mode!="FT4"
&& !m_mode.startsWith ("FST4")) {
//Pad 22-char msg to at least 37 chars //Pad 22-char msg to at least 37 chars
line_read = line_read.left(44) + " " + line_read.mid(44); line_read = line_read.left(44) + " " + line_read.mid(44);
} }
@ -3486,9 +3513,8 @@ void MainWindow::readFromStdout() //readFromStdout
bool okToPost=(nsec > int(4*m_TRperiod)/5); bool okToPost=(nsec > int(4*m_TRperiod)/5);
if(m_mode=="FST4W" and okToPost) { if(m_mode=="FST4W" and okToPost) {
line_read=line_read.left(22) + " CQ " + line_read.trimmed().mid(22); line_read=line_read.left(22) + " CQ " + line_read.trimmed().mid(22);
int n=line_read.trimmed().size(); auto p = line_read.lastIndexOf (' ');
line_read=line_read.trimmed().left(n-3); DecodedText FST4W_post {QString::fromUtf8 (line_read.left (p).constData ())};
DecodedText FST4W_post {QString::fromUtf8(line_read.constData())};
pskPost(FST4W_post); pskPost(FST4W_post);
} else { } else {
if (stdMsg && okToPost) pskPost(decodedtext); if (stdMsg && okToPost) pskPost(decodedtext);
@ -3721,15 +3747,11 @@ void MainWindow::guiUpdate()
if(m_mode=="WSPR" or m_mode=="FST4W") { if(m_mode=="WSPR" or m_mode=="FST4W") {
if(m_nseq==0 and m_ntr==0) { //Decide whether to Tx or Rx if(m_nseq==0 and m_ntr==0) { //Decide whether to Tx or Rx
m_tuneup=false; //This is not an ATU tuneup m_tuneup=false; //This is not an ATU tuneup
if(ui->sbTxPercent->isEnabled () && m_pctx==0) m_WSPR_tx_next = false; //Don't transmit if m_pctx=0
bool btx = m_auto && m_WSPR_tx_next; // To Tx, we need m_auto and bool btx = m_auto && m_WSPR_tx_next; // To Tx, we need m_auto and
// scheduled transmit // scheduled transmit
if(m_auto and m_txNext) btx=true; //TxNext button overrides m_WSPR_tx_next = false;
if(m_auto && ui->sbTxPercent->isEnabled () && m_pctx==100) btx=true; //Always transmit
if(btx) { if(btx) {
m_ntr=-1; //This says we will have transmitted m_ntr=-1; //This says we will have transmitted
m_txNext=false;
ui->pbTxNext->setChecked (false); ui->pbTxNext->setChecked (false);
m_bTxTime=true; //Start a WSPR or FST4W Tx sequence m_bTxTime=true; //Start a WSPR or FST4W Tx sequence
} else { } else {
@ -4276,11 +4298,11 @@ void MainWindow::guiUpdate()
m_nsendingsh=0; m_nsendingsh=0;
if(s[4]==64) m_nsendingsh=1; if(s[4]==64) m_nsendingsh=1;
if(m_nsendingsh==1 or m_currentMessageType==7) { if(m_nsendingsh==1 or m_currentMessageType==7) {
tx_status_label.setStyleSheet("QLabel{background-color: #66ffff}"); tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #66ffff}");
} else if(m_nsendingsh==-1 or m_currentMessageType==6) { } else if(m_nsendingsh==-1 or m_currentMessageType==6) {
tx_status_label.setStyleSheet("QLabel{background-color: #ffccff}"); tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #ffccff}");
} else { } else {
tx_status_label.setStyleSheet("QLabel{background-color: #ffff33}"); tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #ffff33}");
} }
if(m_tune) { if(m_tune) {
tx_status_label.setText("Tx: TUNE"); tx_status_label.setText("Tx: TUNE");
@ -4299,11 +4321,11 @@ void MainWindow::guiUpdate()
} }
} else if(m_monitoring) { } else if(m_monitoring) {
if (!m_tx_watchdog) { if (!m_tx_watchdog) {
tx_status_label.setStyleSheet("QLabel{background-color: #00ff00}"); tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #00ff00}");
auto t = tr ("Receiving"); auto t = tr ("Receiving");
if(m_mode=="MSK144") { if(m_mode=="MSK144") {
int npct=int(100.0*m_fCPUmskrtd/0.298667); int npct=int(100.0*m_fCPUmskrtd/0.298667);
if(npct>90) tx_status_label.setStyleSheet("QLabel{background-color: #ff0000}"); if(npct>90) tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #ff0000}");
t += QString {" %1%"}.arg (npct, 2); t += QString {" %1%"}.arg (npct, 2);
} }
tx_status_label.setText (t); tx_status_label.setText (t);
@ -5017,7 +5039,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie
// m_nextGrid=message_words.at(3); // m_nextGrid=message_words.at(3);
// m_nextRpt=message.report(); // m_nextRpt=message.report();
// ui->labNextCall->setText("Next: " + m_nextCall); // ui->labNextCall->setText("Next: " + m_nextCall);
// ui->labNextCall->setStyleSheet("QLabel {background-color: #66ff66}"); // ui->labNextCall->setStyleSheet("QLabel {color: #000000; background-color: #66ff66}");
// } // }
return; return;
} }
@ -5742,8 +5764,6 @@ void MainWindow::on_tx6_editingFinished() //tx6 edited
void MainWindow::on_RoundRobin_currentTextChanged(QString text) void MainWindow::on_RoundRobin_currentTextChanged(QString text)
{ {
ui->sbTxPercent->setEnabled (text == tr ("Random")); ui->sbTxPercent->setEnabled (text == tr ("Random"));
m_WSPR_tx_next = false; // cancel any pending Tx to avoid
// undesirable consecutive Tx periods
} }
@ -6852,7 +6872,11 @@ void MainWindow::band_changed (Frequency f)
} }
m_lastBand.clear (); m_lastBand.clear ();
m_bandEdited = false; m_bandEdited = false;
m_psk_Reporter.sendReport(); // Upload any queued spots before changing band if (m_config.spot_to_psk_reporter ())
{
// Upload any queued spots before changing band
m_psk_Reporter.sendReport();
}
if (!m_transmitting) monitor (true); if (!m_transmitting) monitor (true);
if ("FreqCal" == m_mode) if ("FreqCal" == m_mode)
{ {
@ -7178,15 +7202,16 @@ void MainWindow::handle_transceiver_update (Transceiver::TransceiverState const&
{ {
Transceiver::TransceiverState old_state {m_rigState}; Transceiver::TransceiverState old_state {m_rigState};
//transmitDisplay (s.ptt ()); //transmitDisplay (s.ptt ());
if (s.ptt () && !m_rigState.ptt ()) { // safe to start audio if (s.ptt () // && !m_rigState.ptt ()
) { // safe to start audio
// (caveat - DX Lab Suite Commander) // (caveat - DX Lab Suite Commander)
if (m_tx_when_ready && g_iptt) { // waiting to Tx and still needed if (m_tx_when_ready && g_iptt) { // waiting to Tx and still needed
int ms_delay=1000*m_config.txDelay(); int ms_delay=1000*m_config.txDelay();
if(m_mode=="FT4") ms_delay=20; if(m_mode=="FT4") ms_delay=20;
ptt1Timer.start(ms_delay); //Start-of-transmission sequencer delay ptt1Timer.start(ms_delay); //Start-of-transmission sequencer delay
}
m_tx_when_ready = false; m_tx_when_ready = false;
} }
}
m_rigState = s; m_rigState = s;
auto old_freqNominal = m_freqNominal; auto old_freqNominal = m_freqNominal;
if (!old_freqNominal) if (!old_freqNominal)
@ -7221,9 +7246,7 @@ void MainWindow::handle_transceiver_update (Transceiver::TransceiverState const&
|| !(ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked()))) { || !(ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked()))) {
m_lastDialFreq = m_freqNominal; m_lastDialFreq = m_freqNominal;
m_secBandChanged=QDateTime::currentMSecsSinceEpoch()/1000; m_secBandChanged=QDateTime::currentMSecsSinceEpoch()/1000;
if (m_config.spot_to_psk_reporter ()) {
pskSetLocal (); pskSetLocal ();
}
statusChanged(); statusChanged();
m_wideGraph->setDialFreq(m_freqNominal / 1.e6); m_wideGraph->setDialFreq(m_freqNominal / 1.e6);
} }
@ -7526,6 +7549,8 @@ bool MainWindow::shortList(QString callsign)
void MainWindow::pskSetLocal () void MainWindow::pskSetLocal ()
{ {
if (!m_config.spot_to_psk_reporter ()) return;
// find the station row, if any, that matches the band we are on // find the station row, if any, that matches the band we are on
auto stations = m_config.stations (); auto stations = m_config.stations ();
auto matches = stations->match (stations->index (0, StationList::band_column) auto matches = stations->match (stations->index (0, StationList::band_column)
@ -8017,8 +8042,8 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout
QString MainWindow::beacon_start_time (int n) QString MainWindow::beacon_start_time (int n)
{ {
auto bt = qt_truncate_date_time_to (QDateTime::currentDateTimeUtc ().addSecs (n), m_TRperiod); auto bt = qt_truncate_date_time_to (QDateTime::currentDateTimeUtc ().addSecs (n), m_TRperiod * 1.e3);
if (m_TRperiod < 60) if (m_TRperiod < 60.)
{ {
return bt.toString ("HHmmss"); return bt.toString ("HHmmss");
} }
@ -8072,17 +8097,18 @@ void MainWindow::uploadWSPRSpots (bool direct_post, QString const& decode_text)
QString rfreq = QString("%1").arg((m_dialFreqRxWSPR + 1500) / 1e6, 0, 'f', 6); QString rfreq = QString("%1").arg((m_dialFreqRxWSPR + 1500) / 1e6, 0, 'f', 6);
QString tfreq = QString("%1").arg((m_dialFreqRxWSPR + QString tfreq = QString("%1").arg((m_dialFreqRxWSPR +
ui->TxFreqSpinBox->value()) / 1e6, 0, 'f', 6); ui->TxFreqSpinBox->value()) / 1e6, 0, 'f', 6);
auto pct = QString::number (ui->autoButton->isChecked () ? ui->sbTxPercent->value () : 0);
if (!direct_post) if (!direct_post)
{ {
wsprNet->upload (m_config.my_callsign (), m_config.my_grid (), rfreq, tfreq, wsprNet->upload (m_config.my_callsign (), m_config.my_grid (), rfreq, tfreq,
m_mode, m_TRperiod, QString::number (ui->autoButton->isChecked () ? m_pctx : 0), m_mode, m_TRperiod, pct,
QString::number (m_dBm), version (), QString::number (m_dBm), version (),
m_config.writeable_data_dir ().absoluteFilePath ("wspr_spots.txt")); m_config.writeable_data_dir ().absoluteFilePath ("wspr_spots.txt"));
} }
else else
{ {
wsprNet->post (m_config.my_callsign (), m_config.my_grid (), rfreq, tfreq, wsprNet->post (m_config.my_callsign (), m_config.my_grid (), rfreq, tfreq,
m_mode, m_TRperiod, QString::number (ui->autoButton->isChecked () ? m_pctx : 0), m_mode, m_TRperiod, pct,
QString::number (m_dBm), version (), decode_text); QString::number (m_dBm), version (), decode_text);
} }
if (!decode_text.size ()) if (!decode_text.size ())
@ -8108,24 +8134,9 @@ void MainWindow::on_TxPowerComboBox_currentIndexChanged(int index)
m_dBm = ui->TxPowerComboBox->itemData (index).toInt (); m_dBm = ui->TxPowerComboBox->itemData (index).toInt ();
} }
void MainWindow::on_sbTxPercent_valueChanged(int n)
{
m_pctx=n;
if(m_pctx>0) {
ui->pbTxNext->setEnabled(true);
} else {
m_txNext=false;
ui->pbTxNext->setChecked(false);
ui->pbTxNext->setEnabled(false);
}
}
void MainWindow::on_cbUploadWSPR_Spots_toggled(bool b) void MainWindow::on_cbUploadWSPR_Spots_toggled(bool b)
{ {
m_uploadWSPRSpots=b; m_uploadWSPRSpots=b;
if(m_uploadWSPRSpots) ui->cbUploadWSPR_Spots->setStyleSheet("");
if(!m_uploadWSPRSpots) ui->cbUploadWSPR_Spots->setStyleSheet(
"QCheckBox{background-color: yellow}");
} }
void MainWindow::on_WSPRfreqSpinBox_valueChanged(int n) void MainWindow::on_WSPRfreqSpinBox_valueChanged(int n)
@ -8135,11 +8146,20 @@ void MainWindow::on_WSPRfreqSpinBox_valueChanged(int n)
void MainWindow::on_pbTxNext_clicked(bool b) void MainWindow::on_pbTxNext_clicked(bool b)
{ {
m_txNext=b; if (b && !ui->autoButton->isChecked ())
{
ui->autoButton->click (); // make sure Tx is possible
}
} }
void MainWindow::WSPR_scheduling () void MainWindow::WSPR_scheduling ()
{ {
if (ui->pbTxNext->isEnabled () && ui->pbTxNext->isChecked ())
{
// Tx Next button overrides all scheduling
m_WSPR_tx_next = true;
return;
}
QString t=ui->RoundRobin->currentText(); QString t=ui->RoundRobin->currentText();
if(m_mode=="FST4W" and t != tr ("Random")) { if(m_mode=="FST4W" and t != tr ("Random")) {
bool ok; bool ok;
@ -8152,10 +8172,14 @@ void MainWindow::WSPR_scheduling ()
int nsec=ms/1000; int nsec=ms/1000;
int ntr=m_TRperiod; int ntr=m_TRperiod;
int j=((nsec+ntr-1) % (n*ntr))/ntr; int j=((nsec+ntr-1) % (n*ntr))/ntr;
m_WSPR_tx_next=(i==j); m_WSPR_tx_next = i == j;
return; return;
} }
m_WSPR_tx_next = false; m_WSPR_tx_next = false;
if (!ui->sbTxPercent->isEnabled () || !ui->sbTxPercent->value ())
{
return; // don't schedule if %age disabled or zero
}
if (m_config.is_transceiver_online () // need working rig control for hopping if (m_config.is_transceiver_online () // need working rig control for hopping
&& !m_config.is_dummy_rig () && !m_config.is_dummy_rig ()
&& ui->band_hopping_group_box->isChecked ()) { && ui->band_hopping_group_box->isChecked ()) {
@ -8442,7 +8466,7 @@ void MainWindow::tx_watchdog (bool triggered)
m_bTxTime=false; m_bTxTime=false;
if (m_tune) stop_tuning (); if (m_tune) stop_tuning ();
if (m_auto) auto_tx_mode (false); if (m_auto) auto_tx_mode (false);
tx_status_label.setStyleSheet ("QLabel{background-color: #ff0000}"); tx_status_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff0000}");
tx_status_label.setText (tr ("Runaway Tx watchdog")); tx_status_label.setText (tr ("Runaway Tx watchdog"));
QApplication::alert (this); QApplication::alert (this);
} }

View File

@ -346,6 +346,7 @@ private:
int TRperiod=60) const; int TRperiod=60) const;
Q_SIGNAL void outAttenuationChanged (qreal) const; Q_SIGNAL void outAttenuationChanged (qreal) const;
Q_SIGNAL void toggleShorthand () const; Q_SIGNAL void toggleShorthand () const;
Q_SIGNAL void reset_audio_input_stream (bool report_dropped_frames) const;
private: private:
void set_mode (QString const& mode); void set_mode (QString const& mode);
@ -445,7 +446,6 @@ private:
qint32 m_nclearave; qint32 m_nclearave;
qint32 m_minSync; qint32 m_minSync;
qint32 m_dBm; qint32 m_dBm;
qint32 m_pctx;
qint32 m_nseq; qint32 m_nseq;
qint32 m_nWSPRdecodes; qint32 m_nWSPRdecodes;
qint32 m_k0; qint32 m_k0;
@ -504,7 +504,6 @@ private:
bool m_bSWL; bool m_bSWL;
bool m_uploadWSPRSpots; bool m_uploadWSPRSpots;
bool m_uploading; bool m_uploading;
bool m_txNext;
bool m_grid6; bool m_grid6;
bool m_tuneup; bool m_tuneup;
bool m_bTxTime; bool m_bTxTime;
@ -666,8 +665,6 @@ private:
QSharedMemory *mem_jt9; QSharedMemory *mem_jt9;
QString m_QSOText; QString m_QSOText;
unsigned m_msAudioOutputBuffered;
unsigned m_framesAudioInputBuffered;
unsigned m_downSampleFactor; unsigned m_downSampleFactor;
QThread::Priority m_audioThreadPriority; QThread::Priority m_audioThreadPriority;
bool m_bandEdited; bool m_bandEdited;

View File

@ -376,6 +376,7 @@
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">QPushButton:checked { <string notr="true">QPushButton:checked {
color: #000000;
background-color: #00ff00; background-color: #00ff00;
border-style: outset; border-style: outset;
border-width: 1px; border-width: 1px;
@ -447,6 +448,7 @@
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">QPushButton:checked { <string notr="true">QPushButton:checked {
color: rgb(0, 0, 0);
background-color: cyan; background-color: cyan;
border-style: outset; border-style: outset;
border-width: 1px; border-width: 1px;
@ -480,6 +482,7 @@
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">QPushButton:checked { <string notr="true">QPushButton:checked {
color: rgb(0, 0, 0);
background-color: red; background-color: red;
border-style: outset; border-style: outset;
border-width: 1px; border-width: 1px;
@ -523,6 +526,7 @@
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">QPushButton:checked { <string notr="true">QPushButton:checked {
color: rgb(0, 0, 0);
background-color: red; background-color: red;
border-style: outset; border-style: outset;
border-width: 1px; border-width: 1px;
@ -997,6 +1001,7 @@ Not available to nonstandard callsign holders.</string>
<widget class="QPushButton" name="pbBestSP"> <widget class="QPushButton" name="pbBestSP">
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">QPushButton:checked { <string notr="true">QPushButton:checked {
color: rgb(0, 0, 0);
background-color: red; background-color: red;
border-style: outset; border-style: outset;
border-width: 1px; border-width: 1px;
@ -2158,6 +2163,12 @@ list. The list can be maintained in Settings (F2).</string>
<property name="toolTip"> <property name="toolTip">
<string>Percentage of minute sequences devoted to transmitting.</string> <string>Percentage of minute sequences devoted to transmitting.</string>
</property> </property>
<property name="styleSheet">
<string notr="true">QSpinBox:enabled[notx=&quot;true&quot;] {
color: rgb(0, 0, 0);
background-color: rgb(255, 255, 0);
}</string>
</property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignCenter</set> <set>Qt::AlignCenter</set>
</property> </property>
@ -2341,6 +2352,12 @@ list. The list can be maintained in Settings (F2).</string>
<property name="toolTip"> <property name="toolTip">
<string>Upload decoded messages to WSPRnet.org.</string> <string>Upload decoded messages to WSPRnet.org.</string>
</property> </property>
<property name="styleSheet">
<string notr="true">QCheckBox:unchecked {
color: rgb(0, 0, 0);
background-color: rgb(255, 255, 0);
}</string>
</property>
<property name="text"> <property name="text">
<string>Upload spots</string> <string>Upload spots</string>
</property> </property>
@ -2380,6 +2397,7 @@ list. The list can be maintained in Settings (F2).</string>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">QPushButton:checked { <string notr="true">QPushButton:checked {
color: rgb(0, 0, 0);
background-color: red; background-color: red;
border-style: outset; border-style: outset;
border-width: 1px; border-width: 1px;
@ -2485,8 +2503,7 @@ list. The list can be maintained in Settings (F2).</string>
} }
QLabel[oob=&quot;true&quot;] { QLabel[oob=&quot;true&quot;] {
background-color: red; background-color: red;
} }</string>
</string>
</property> </property>
<property name="text"> <property name="text">
<string>14.078 000</string> <string>14.078 000</string>