mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-30 20:40:28 -04:00 
			
		
		
		
	Merge branch 'develop' into feat-fst280
This commit is contained in:
		
						commit
						4a2a181528
					
				
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,6 +1,9 @@ | ||||
| ~* | ||||
| TAGS | ||||
| tags | ||||
| GPATH | ||||
| GRTAGS | ||||
| GTAGS | ||||
| *~ | ||||
| junk* | ||||
| jnq* | ||||
| @ -9,6 +12,9 @@ jnq* | ||||
| *.mod | ||||
| *.pro.user | ||||
| *.txt | ||||
| *.bak | ||||
| !**/CMakeLists.txt | ||||
| __pycache__ | ||||
| cmake-build-debug | ||||
| cmake-build-release | ||||
| CMakeFiles | ||||
|  | ||||
| @ -43,23 +43,23 @@ protected: | ||||
|     qint16 const * begin (reinterpret_cast<qint16 const *> (source)); | ||||
|     for ( qint16 const * i = begin; i != begin + numFrames * (bytesPerFrame () / sizeof (qint16)); i += bytesPerFrame () / sizeof (qint16)) | ||||
|       { | ||||
| 	switch (m_channel) | ||||
| 	  { | ||||
| 	  case Mono: | ||||
| 	    *dest++ = *i; | ||||
| 	    break; | ||||
|         switch (m_channel) | ||||
|           { | ||||
|           case Mono: | ||||
|             *dest++ = *i; | ||||
|             break; | ||||
| 
 | ||||
| 	  case Right: | ||||
| 	    *dest++ = *(i + 1); | ||||
| 	    break; | ||||
|           case Right: | ||||
|             *dest++ = *(i + 1); | ||||
|             break; | ||||
| 
 | ||||
| 	  case Both:		// should be able to happen but if it
 | ||||
| 				// does we'll take left
 | ||||
| 	    Q_ASSERT (Both == m_channel); | ||||
| 	  case Left: | ||||
| 	    *dest++ = *i; | ||||
| 	    break; | ||||
| 	  } | ||||
|           case Both:    // should be able to happen but if it
 | ||||
|             // does we'll take left
 | ||||
|             Q_ASSERT (Both == m_channel); | ||||
|           case Left: | ||||
|             *dest++ = *i; | ||||
|             break; | ||||
|           } | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
| @ -68,23 +68,23 @@ protected: | ||||
|     switch (m_channel) | ||||
|       { | ||||
|       case Mono: | ||||
| 	*dest++ = sample; | ||||
| 	break; | ||||
|         *dest++ = sample; | ||||
|         break; | ||||
| 
 | ||||
|       case Left: | ||||
| 	*dest++ = sample; | ||||
| 	*dest++ = 0; | ||||
| 	break; | ||||
|         *dest++ = sample; | ||||
|         *dest++ = 0; | ||||
|         break; | ||||
| 
 | ||||
|       case Right: | ||||
| 	*dest++ = 0; | ||||
| 	*dest++ = sample; | ||||
| 	break; | ||||
|         *dest++ = 0; | ||||
|         *dest++ = sample; | ||||
|         break; | ||||
| 
 | ||||
|       case Both: | ||||
| 	*dest++ = sample; | ||||
| 	*dest++ = sample; | ||||
| 	break; | ||||
|         *dest++ = sample; | ||||
|         *dest++ = sample; | ||||
|         break; | ||||
|       } | ||||
|     return dest; | ||||
|   } | ||||
|  | ||||
| @ -41,7 +41,8 @@ bool SoundInput::audioError () const | ||||
|   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); | ||||
| 
 | ||||
| @ -62,14 +63,13 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi | ||||
|       Q_EMIT error (tr ("Requested input audio format is not valid.")); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|   if (!device.isFormatSupported (format)) | ||||
|   else if (!device.isFormatSupported (format)) | ||||
|     { | ||||
| //      qDebug () << "Nearest supported audio format:" << device.nearestFormat (format);
 | ||||
|       Q_EMIT error (tr ("Requested input audio format is not supported on device.")); | ||||
|       return; | ||||
|     } | ||||
| //  qDebug () << "Selected audio input format:" << format;
 | ||||
|   // qDebug () << "Selected audio input format:" << format;
 | ||||
| 
 | ||||
|   m_stream.reset (new QAudioInput {device, format}); | ||||
|   if (audioError ()) | ||||
| @ -79,11 +79,20 @@ void SoundInput::start(QAudioDeviceInfo const& device, int framesPerBuffer, Audi | ||||
| 
 | ||||
|   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)) | ||||
|     { | ||||
|       m_stream->start (sink); | ||||
|       audioError (); | ||||
|       cummulative_lost_usec_ = -1; | ||||
|       //qDebug () << "SoundIn selected buffer size (bytes):" << m_stream->bufferSize () << "peirod size:" << m_stream->periodSize ();
 | ||||
|     } | ||||
|   else | ||||
|     { | ||||
| @ -115,9 +124,9 @@ 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;
 | ||||
| 
 | ||||
|   switch (newState) | ||||
|     { | ||||
| @ -126,6 +135,7 @@ void SoundInput::handleStateChanged (QAudio::State newState) const | ||||
|       break; | ||||
| 
 | ||||
|     case QAudio::ActiveState: | ||||
|       reset (false); | ||||
|       Q_EMIT status (tr ("Receiving")); | ||||
|       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() | ||||
| { | ||||
|   if (m_stream) | ||||
|  | ||||
| @ -24,6 +24,7 @@ public: | ||||
|   SoundInput (QObject * parent = nullptr) | ||||
|     : QObject {parent} | ||||
|     , m_sink {nullptr} | ||||
|     , cummulative_lost_usec_ {0} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
| @ -35,18 +36,21 @@ public: | ||||
|   Q_SLOT void suspend (); | ||||
|   Q_SLOT void resume (); | ||||
|   Q_SLOT void stop (); | ||||
|   Q_SLOT void reset (bool report_dropped_frames); | ||||
| 
 | ||||
|   Q_SIGNAL void error (QString message) const; | ||||
|   Q_SIGNAL void status (QString message) const; | ||||
|   Q_SIGNAL void dropped_frames (qint32 dropped, qint64 usec); | ||||
| 
 | ||||
| private: | ||||
|   // used internally
 | ||||
|   Q_SLOT void handleStateChanged (QAudio::State) const; | ||||
|   Q_SLOT void handleStateChanged (QAudio::State); | ||||
| 
 | ||||
|   bool audioError () const; | ||||
| 
 | ||||
|   QScopedPointer<QAudioInput> m_stream; | ||||
|   QPointer<AudioDevice> m_sink; | ||||
|   qint64 cummulative_lost_usec_; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -9,15 +9,6 @@ | ||||
| 
 | ||||
| #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 result (true); | ||||
| @ -50,62 +41,76 @@ bool SoundOutput::audioError () const | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, unsigned msBuffered) | ||||
| void SoundOutput::setFormat (QAudioDeviceInfo const& device, unsigned channels, int frames_buffered) | ||||
| { | ||||
|   Q_ASSERT (0 < channels && channels < 3); | ||||
| 
 | ||||
|   m_msBuffered = msBuffered; | ||||
| 
 | ||||
|   QAudioFormat format (device.preferredFormat ()); | ||||
| //  qDebug () << "Preferred audio output format:" << format;
 | ||||
|   format.setChannelCount (channels); | ||||
|   format.setCodec ("audio/pcm"); | ||||
|   format.setSampleRate (48000); | ||||
|   format.setSampleType (QAudioFormat::SignedInt); | ||||
|   format.setSampleSize (16); | ||||
|   format.setByteOrder (QAudioFormat::Endian (QSysInfo::ByteOrder)); | ||||
|   if (!format.isValid ()) | ||||
|   if (!device.isNull ()) | ||||
|     { | ||||
|       Q_EMIT error (tr ("Requested output audio format is not valid.")); | ||||
|       Q_ASSERT (0 < channels && channels < 3); | ||||
| 
 | ||||
|       m_framesBuffered = frames_buffered; | ||||
| 
 | ||||
|       QAudioFormat format (device.preferredFormat ()); | ||||
|       //  qDebug () << "Preferred audio output format:" << format;
 | ||||
|       format.setChannelCount (channels); | ||||
|       format.setCodec ("audio/pcm"); | ||||
|       format.setSampleRate (48000); | ||||
|       format.setSampleType (QAudioFormat::SignedInt); | ||||
|       format.setSampleSize (16); | ||||
|       format.setByteOrder (QAudioFormat::Endian (QSysInfo::ByteOrder)); | ||||
|       if (!format.isValid ()) | ||||
|         { | ||||
|           Q_EMIT error (tr ("Requested output audio format is not valid.")); | ||||
|         } | ||||
|       else if (!device.isFormatSupported (format)) | ||||
|         { | ||||
|           Q_EMIT error (tr ("Requested output audio format is not supported on device.")); | ||||
|         } | ||||
|       else | ||||
|         { | ||||
|           // qDebug () << "Selected audio output format:" << format;
 | ||||
| 
 | ||||
|           m_stream.reset (new QAudioOutput (device, format)); | ||||
|           audioError (); | ||||
|           m_stream->setVolume (m_volume); | ||||
|           m_stream->setNotifyInterval(100); | ||||
|           error_ = false; | ||||
| 
 | ||||
|           connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged); | ||||
| 
 | ||||
|           //      qDebug() << "A" << m_volume << m_stream->notifyInterval();
 | ||||
|         } | ||||
|     } | ||||
|   if (!device.isFormatSupported (format)) | ||||
|     { | ||||
|       Q_EMIT error (tr ("Requested output audio format is not supported on device.")); | ||||
|     } | ||||
| //  qDebug () << "Selected audio output format:" << format;
 | ||||
| 
 | ||||
|   m_stream.reset (new QAudioOutput (device, format)); | ||||
|   audioError (); | ||||
|   m_stream->setVolume (m_volume); | ||||
|   m_stream->setNotifyInterval(100); | ||||
| 
 | ||||
|   connect (m_stream.data(), &QAudioOutput::stateChanged, this, &SoundOutput::handleStateChanged); | ||||
| 
 | ||||
|   //      qDebug() << "A" << m_volume << m_stream->notifyInterval();
 | ||||
| } | ||||
| 
 | ||||
| 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
 | ||||
|   // Windows implementation seems to forget the buffer size after a
 | ||||
|   // stop.
 | ||||
|   m_stream->setBufferSize (m_stream->format().bytesForDuration((m_msBuffered ? m_msBuffered : MS_BUFFERED) * 1000)); | ||||
|   //  qDebug() << "B" << m_stream->bufferSize() <<
 | ||||
|   //  m_stream->periodSize() << m_stream->notifyInterval();
 | ||||
|   //qDebug () << "SoundOut default buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
 | ||||
|   if (m_framesBuffered) | ||||
|     { | ||||
| #if defined (Q_OS_WIN) | ||||
|       m_stream->setBufferSize (m_stream->format().bytesForFrames (m_framesBuffered)); | ||||
| #endif | ||||
|     } | ||||
|   m_stream->setCategory ("production"); | ||||
|   m_stream->start (source); | ||||
|   // qDebug () << "SoundOut selected buffer size (bytes):" << m_stream->bufferSize () << "period size:" << m_stream->periodSize ();
 | ||||
| } | ||||
| 
 | ||||
| void SoundOutput::suspend () | ||||
|  | ||||
| @ -18,15 +18,16 @@ class SoundOutput | ||||
|    | ||||
| public: | ||||
|   SoundOutput () | ||||
|     : m_msBuffered {0u} | ||||
|     : m_framesBuffered {0} | ||||
|     , m_volume {1.0} | ||||
|     , error_ {false} | ||||
|   { | ||||
|   } | ||||
| 
 | ||||
|   qreal attenuation () const; | ||||
| 
 | ||||
| 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 suspend (); | ||||
|   void resume (); | ||||
| @ -47,8 +48,9 @@ private Q_SLOTS: | ||||
| 
 | ||||
| private: | ||||
|   QScopedPointer<QAudioOutput> m_stream; | ||||
|   unsigned m_msBuffered; | ||||
|   int m_framesBuffered; | ||||
|   qreal m_volume; | ||||
|   bool error_; | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -222,9 +222,12 @@ set (WSJT_QT_CONF_DESTINATION ${QT_CONF_DESTINATION} CACHE PATH "Path for the qt | ||||
| # | ||||
| # Project sources | ||||
| # | ||||
| set (fort_qt_CXXSRCS | ||||
|   lib/shmem.cpp | ||||
|   ) | ||||
| 
 | ||||
| set (wsjt_qt_CXXSRCS | ||||
|   qt_helpers.cpp | ||||
|   lib/shmem.cpp | ||||
|   widgets/MessageBox.cpp | ||||
|   MetaDataRegistry.cpp | ||||
|   Network/NetworkServerLookup.cpp | ||||
| @ -733,6 +736,7 @@ set (qcp_CXXSRCS | ||||
| 
 | ||||
| set (all_CXXSRCS | ||||
|   ${wsjt_CXXSRCS} | ||||
|   ${fort_qt_CXXSRCS} | ||||
|   ${wsjt_qt_CXXSRCS} | ||||
|   ${wsjt_qtmm_CXXSRCS} | ||||
|   ${wsjtx_CXXSRCS} | ||||
| @ -747,7 +751,6 @@ set (all_C_and_CXXSRCS | ||||
|   ) | ||||
| 
 | ||||
| set (TOP_LEVEL_RESOURCES | ||||
|   cty.dat | ||||
|   icons/Darwin/wsjtx.iconset/icon_128x128.png | ||||
|   contrib/gpl-v3-logo.svg | ||||
|   artwork/splash.png | ||||
| @ -888,7 +891,7 @@ find_package (OpenMP) | ||||
| # | ||||
| # fftw3 single precision library | ||||
| # | ||||
| find_package (FFTW3 COMPONENTS double single threads REQUIRED) | ||||
| find_package (FFTW3 COMPONENTS single threads REQUIRED) | ||||
| 
 | ||||
| # | ||||
| # libhamlib setup | ||||
| @ -929,7 +932,9 @@ endif () | ||||
| if (WSJT_GENERATE_DOCS) | ||||
|   add_subdirectory (doc) | ||||
| endif (WSJT_GENERATE_DOCS) | ||||
| 
 | ||||
| if (EXISTS ${CMAKE_SOURCE_DIR}/tests AND IS_DIRECTORY ${CMAKE_SOURCE_DIR}/tests) | ||||
|   add_subdirectory (tests) | ||||
| endif () | ||||
| 
 | ||||
| # | ||||
| # Library building setup | ||||
| @ -1259,6 +1264,11 @@ if (WIN32) | ||||
|   target_link_libraries (wsjt_qt Qt5::AxContainer Qt5::AxBase) | ||||
| 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}) | ||||
| target_link_libraries (wsjt_qtmm Qt5::Multimedia) | ||||
| 
 | ||||
| @ -1306,9 +1316,9 @@ if (${OPENMP_FOUND} OR APPLE) | ||||
|       LINK_FLAGS -Wl,--stack,16777216 | ||||
|       ) | ||||
|   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) | ||||
|   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) | ||||
| 
 | ||||
| if(WSJT_BUILD_UTILS)  | ||||
| @ -1572,6 +1582,7 @@ install (FILES | ||||
|   ) | ||||
| 
 | ||||
| install (FILES | ||||
|   cty.dat | ||||
|   contrib/Ephemeris/JPLEPH | ||||
|   DESTINATION ${CMAKE_INSTALL_DATADIR}/${CMAKE_PROJECT_NAME} | ||||
|   #COMPONENT runtime | ||||
| @ -1852,11 +1863,11 @@ endif () | ||||
| 
 | ||||
| set (CPACK_DEBIAN_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") | ||||
| set (CPACK_DEBIAN_PACKAGE_HOMEPAGE "${PROJECT_HOMEPAGE}") | ||||
| set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran4 (>=7.3.0), libfftw3-single3 (>=3.3.7), libgomp1 (>8), libqt5serialport5 (>=5.9.5), libqt5multimedia5-plugins (>=5.9.5), libqt5widgets5 (>=5.9.5), libqt5network5 (>=5.9.5), libqt5printsupport5 (>=5.9.5), libqt5sql5-sqlite (>=5.9.5), libusb-1.0-0 (>=1.0.21)") | ||||
| set (CPACK_DEBIAN_PACKAGE_DEPENDS "libgfortran5 (>=10), libfftw3-single3 (>=3.3.8), libgomp1 (>=10), libqt5serialport5 (>=5.12.8), libqt5multimedia5-plugins (>=5.12.8), libqt5widgets5 (>=5.12.8), libqt5network5 (>=5.12.8), libqt5printsupport5 (>=5.12.8), libqt5sql5-sqlite (>=5.12.8), libusb-1.0-0 (>=1.0.23)") | ||||
| set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) | ||||
| 
 | ||||
| set (CPACK_RPM_PACKAGE_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) | ||||
| set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtbase >= 5.6, qt5-qtserialport >= 5.6, qt5-qtmultimedia >= 5.6, qt5-qtsvg >= 5.6, libusbx >= 1.0.23, libgfortran >= 4.7, fftw-libs-double > 3.3.8, fftw-libs-single > 3.3.8") | ||||
| set (CPACK_RPM_PACKAGE_REQUIRES "qt5-qtbase >= 5.13.2, qt5-qtserialport >= 5.13.2, qt5-qtmultimedia >= 5.13.2, qt5-qtsvg >= 5.13.2, libusbx >= 1.0.23, libgfortran >= 10.0.1, libgomp >= 10.0.1, fftw-libs-single >= 3.3.8") | ||||
| set (CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/share/pixmaps /usr/share/applications /usr/share/man /usr/share/man1) | ||||
| 
 | ||||
| configure_file ("${PROJECT_SOURCE_DIR}/CMakeCPackOptions.cmake.in" | ||||
|  | ||||
| @ -137,6 +137,8 @@ | ||||
| #include <QApplication> | ||||
| #include <QMetaType> | ||||
| #include <QList> | ||||
| #include <QPair> | ||||
| #include <QVariant> | ||||
| #include <QSettings> | ||||
| #include <QAudioDeviceInfo> | ||||
| #include <QAudioInput> | ||||
| @ -401,6 +403,7 @@ class Configuration::impl final | ||||
| public: | ||||
|   using FrequencyDelta = Radio::FrequencyDelta; | ||||
|   using port_type = Configuration::port_type; | ||||
|   using audio_info_type = QPair<QAudioDeviceInfo, QList<QVariant> >; | ||||
| 
 | ||||
|   explicit impl (Configuration * self | ||||
|                  , QNetworkAccessManager * network_manager | ||||
| @ -429,9 +432,14 @@ private: | ||||
|   void read_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 find_tab (QWidget *); | ||||
| 
 | ||||
|   void initialize_models (); | ||||
|   bool split_mode () const | ||||
|   { | ||||
| @ -477,8 +485,6 @@ private: | ||||
|   Q_SLOT void on_force_DTR_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_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_delete_macro_push_button_clicked (bool = false); | ||||
|   Q_SLOT void on_PTT_method_button_group_buttonClicked (int); | ||||
| @ -647,10 +653,8 @@ private: | ||||
|   bool pwrBandTuneMemory_; | ||||
| 
 | ||||
|   QAudioDeviceInfo audio_input_device_; | ||||
|   bool default_audio_input_device_selected_; | ||||
|   AudioDevice::Channel audio_input_channel_; | ||||
|   QAudioDeviceInfo audio_output_device_; | ||||
|   bool default_audio_output_device_selected_; | ||||
|   AudioDevice::Channel audio_output_channel_; | ||||
| 
 | ||||
|   friend class Configuration; | ||||
| @ -976,8 +980,6 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network | ||||
|   , transceiver_command_number_ {0} | ||||
|   , degrade_ {0.}               // initialize to zero each run, not
 | ||||
|                                 // saved in settings
 | ||||
|   , default_audio_input_device_selected_ {false} | ||||
|   , default_audio_output_device_selected_ {false} | ||||
| { | ||||
|   ui_->setupUi (this); | ||||
| 
 | ||||
| @ -1100,6 +1102,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network | ||||
|   //
 | ||||
|   // 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::placeholders; | ||||
| @ -1130,7 +1133,9 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network | ||||
| 
 | ||||
|   ui_->frequencies_table_view->setModel (&next_frequencies_); | ||||
|   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 ()->setResizeContentsPrecision (0); | ||||
|   ui_->frequencies_table_view->sortByColumn (FrequencyList_v2::frequency_column, Qt::AscendingOrder); | ||||
|   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); | ||||
|   ui_->stations_table_view->setModel (&next_stations_); | ||||
|   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 ()->setResizeContentsPrecision (0); | ||||
|   ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder); | ||||
| 
 | ||||
|   // stations delegates
 | ||||
| @ -1189,18 +1196,6 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network | ||||
|   //
 | ||||
|   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 (); | ||||
|   initialize_models (); | ||||
| 
 | ||||
| @ -1215,8 +1210,35 @@ Configuration::impl::~impl () | ||||
|   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 () | ||||
| { | ||||
|   { | ||||
|     SettingsGroup g {settings_, "Configuration"}; | ||||
|     find_audio_devices (); | ||||
|   } | ||||
|   auto pal = ui_->callsign_line_edit->palette (); | ||||
|   if (my_callsign_.isEmpty ()) | ||||
|     { | ||||
| @ -1238,6 +1260,7 @@ void Configuration::impl::initialize_models () | ||||
|   ui_->sbDegrade->setValue (degrade_); | ||||
|   ui_->sbBandwidth->setValue (RxBandwidth_); | ||||
|   ui_->PTT_method_button_group->button (rig_params_.ptt_type)->setChecked (true); | ||||
| 
 | ||||
|   ui_->save_path_display_label->setText (save_directory_.absolutePath ()); | ||||
|   ui_->azel_path_display_label->setText (azel_directory_.absolutePath ()); | ||||
|   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 ()); | ||||
|   azel_directory_.setPath (settings_->value ("AzElDir", default_azel_directory_.absolutePath ()).toString ()); | ||||
| 
 | ||||
|   { | ||||
|     //
 | ||||
|     // 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 ()); | ||||
|   find_audio_devices (); | ||||
| 
 | ||||
|   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 (); | ||||
| } | ||||
| 
 | ||||
| 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 () | ||||
| { | ||||
|   SettingsGroup g {settings_, "Configuration"}; | ||||
| @ -1566,25 +1556,8 @@ void Configuration::impl::write_settings () | ||||
|   settings_->setValue ("PTTport", rig_params_.ptt_port); | ||||
|   settings_->setValue ("SaveDir", save_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 ()); | ||||
|     } | ||||
| 
 | ||||
|   if (default_audio_output_device_selected_) | ||||
|     { | ||||
|       settings_->setValue ("SoundOutName", QAudioDeviceInfo::defaultOutputDevice ().deviceName ()); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       settings_->setValue ("SoundOutName", audio_output_device_.deviceName ()); | ||||
|     } | ||||
| 
 | ||||
|   settings_->setValue ("SoundInName", audio_input_device_.deviceName ()); | ||||
|   settings_->setValue ("SoundOutName", audio_output_device_.deviceName ()); | ||||
|   settings_->setValue ("AudioInputChannel", AudioDevice::toString (audio_input_channel_)); | ||||
|   settings_->setValue ("AudioOutputChannel", AudioDevice::toString (audio_output_channel_)); | ||||
|   settings_->setValue ("Type2MsgGen", QVariant::fromValue (type_2_msg_gen_)); | ||||
| @ -1658,6 +1631,7 @@ void Configuration::impl::write_settings () | ||||
|   settings_->setValue ("pwrBandTuneMemory", pwrBandTuneMemory_); | ||||
|   settings_->setValue ("Region", QVariant::fromValue (region_)); | ||||
|   settings_->setValue ("AutoGrid", use_dynamic_grid_); | ||||
|   settings_->sync (); | ||||
| } | ||||
| 
 | ||||
| void Configuration::impl::set_rig_invariants () | ||||
| @ -1790,17 +1764,27 @@ void Configuration::impl::set_rig_invariants () | ||||
| bool Configuration::impl::validate () | ||||
| { | ||||
|   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")); | ||||
|       return false; | ||||
|     } | ||||
| 
 | ||||
|   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")); | ||||
|       return false; | ||||
|       find_tab (ui_->sound_output_combo_box); | ||||
|       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 ()) | ||||
| @ -1822,16 +1806,7 @@ bool Configuration::impl::validate () | ||||
|   if (ui_->rbField_Day->isEnabled () && ui_->rbField_Day->isChecked () && | ||||
|       !ui_->Field_Day_Exchange->hasAcceptableInput ()) | ||||
|     { | ||||
|       for (auto * parent = ui_->Field_Day_Exchange->parentWidget (); parent; parent = parent->parentWidget ()) | ||||
|         { | ||||
|           auto index = ui_->configuration_tabs->indexOf (parent); | ||||
|           if (index != -1) | ||||
|             { | ||||
|               ui_->configuration_tabs->setCurrentIndex (index); | ||||
|               break; | ||||
|             } | ||||
|         } | ||||
|       ui_->Field_Day_Exchange->setFocus (); | ||||
|       find_tab (ui_->Field_Day_Exchange); | ||||
|       MessageBox::critical_message (this, tr ("Invalid Contest Exchange") | ||||
|                                     , tr ("You must input a valid ARRL Field Day exchange")); | ||||
|       return false; | ||||
| @ -1840,16 +1815,7 @@ bool Configuration::impl::validate () | ||||
|   if (ui_->rbRTTY_Roundup->isEnabled () && ui_->rbRTTY_Roundup->isChecked () && | ||||
|       !ui_->RTTY_Exchange->hasAcceptableInput ()) | ||||
|     { | ||||
|       for (auto * parent = ui_->RTTY_Exchange->parentWidget (); parent; parent = parent->parentWidget ()) | ||||
|         { | ||||
|           auto index = ui_->configuration_tabs->indexOf (parent); | ||||
|           if (index != -1) | ||||
|             { | ||||
|               ui_->configuration_tabs->setCurrentIndex (index); | ||||
|               break; | ||||
|             } | ||||
|         } | ||||
|       ui_->RTTY_Exchange->setFocus (); | ||||
|       find_tab (ui_->RTTY_Exchange); | ||||
|       MessageBox::critical_message (this, tr ("Invalid Contest Exchange") | ||||
|                                     , tr ("You must input a valid ARRL RTTY Roundup exchange")); | ||||
|       return false; | ||||
| @ -1970,59 +1936,19 @@ void Configuration::impl::accept () | ||||
|   // Check to see whether SoundInThread must be restarted,
 | ||||
|   // and save user parameters.
 | ||||
|   { | ||||
|     auto const& device_name = ui_->sound_input_combo_box->currentText (); | ||||
|     if (device_name != audio_input_device_.deviceName ()) | ||||
|     auto const& selected_device = ui_->sound_input_combo_box->currentData ().value<audio_info_type> ().first; | ||||
|     if (selected_device != audio_input_device_) | ||||
|       { | ||||
|         auto const& default_device = QAudioDeviceInfo::defaultInputDevice (); | ||||
|         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; | ||||
|               } | ||||
|           } | ||||
|         audio_input_device_ = selected_device; | ||||
|         restart_sound_input_device_ = true; | ||||
|       } | ||||
|   } | ||||
| 
 | ||||
|   { | ||||
|     auto const& device_name = ui_->sound_output_combo_box->currentText (); | ||||
|     if (device_name != audio_output_device_.deviceName ()) | ||||
|     auto const& selected_device = ui_->sound_output_combo_box->currentData ().value<audio_info_type> ().first; | ||||
|     if (selected_device != audio_output_device_) | ||||
|       { | ||||
|         auto const& default_device = QAudioDeviceInfo::defaultOutputDevice (); | ||||
|         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; | ||||
|               } | ||||
|           } | ||||
|         audio_output_device_ = selected_device; | ||||
|         restart_sound_output_device_ = true; | ||||
|       } | ||||
|   } | ||||
| @ -2306,16 +2232,6 @@ void Configuration::impl::on_PTT_method_button_group_buttonClicked (int /* id */ | ||||
|   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 () | ||||
| { | ||||
|   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); | ||||
|   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_); | ||||
| } | ||||
| 
 | ||||
| @ -2719,6 +2636,7 @@ void Configuration::impl::transceiver_tx_frequency (Frequency f) | ||||
|           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_); | ||||
|     } | ||||
| } | ||||
| @ -2727,6 +2645,7 @@ void Configuration::impl::transceiver_mode (MODE m) | ||||
| { | ||||
|   cached_rig_state_.online (true); // we want the rig online
 | ||||
|   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_); | ||||
| } | ||||
| 
 | ||||
| @ -2735,6 +2654,7 @@ void Configuration::impl::transceiver_ptt (bool on) | ||||
|   cached_rig_state_.online (true); // we want the rig online
 | ||||
|   set_cached_mode (); | ||||
|   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_); | ||||
| } | ||||
| 
 | ||||
| @ -2833,72 +2753,67 @@ void Configuration::impl::close_rig () | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // load the available audio devices into the selection combo box and
 | ||||
| // select the default device if the current device isn't set or isn't
 | ||||
| // available
 | ||||
| bool Configuration::impl::load_audio_devices (QAudio::Mode mode, QComboBox * combo_box, QAudioDeviceInfo * device) | ||||
| // find the audio device that matches the specified name, also
 | ||||
| // populate into the selection combo box with any devices we find in
 | ||||
| // the search
 | ||||
| QAudioDeviceInfo Configuration::impl::find_audio_device (QAudio::Mode mode, QComboBox * combo_box | ||||
|                                                          , QString const& device_name) | ||||
| { | ||||
|   using std::copy; | ||||
|   using std::back_inserter; | ||||
| 
 | ||||
|   bool result {false}; | ||||
| 
 | ||||
|   combo_box->clear (); | ||||
| 
 | ||||
|   int current_index = -1; | ||||
|   int default_index = -1; | ||||
| 
 | ||||
|   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 ()) | ||||
|   auto const& devices = QAudioDeviceInfo::availableDevices (mode); | ||||
|   Q_FOREACH (auto const& p, devices) | ||||
|     { | ||||
|       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 ();
 | ||||
| 
 | ||||
|       // 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 (), 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) | ||||
|         { | ||||
|           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); | ||||
| 
 | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| // 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); | ||||
|     } | ||||
| 
 | ||||
|   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
 | ||||
|       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
 | ||||
| void Configuration::impl::enumerate_rigs () | ||||
| { | ||||
|  | ||||
							
								
								
									
										156
									
								
								Configuration.ui
									
									
									
									
									
								
							
							
						
						
									
										156
									
								
								Configuration.ui
									
									
									
									
									
								
							| @ -6,8 +6,8 @@ | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>559</width> | ||||
|     <height>553</height> | ||||
|     <width>554</width> | ||||
|     <height>557</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
| @ -1349,33 +1349,13 @@ radio interface behave as expected.</string> | ||||
|           <string>Soundcard</string> | ||||
|          </property> | ||||
|          <layout class="QGridLayout" name="gridLayout_6"> | ||||
|           <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> | ||||
|           <item row="1" column="0"> | ||||
|            <widget class="QLabel" name="sound_output_label"> | ||||
|             <property name="text"> | ||||
|              <string>Ou&tput:</string> | ||||
|             </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="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 name="buddy"> | ||||
|              <cstring>sound_output_combo_box</cstring> | ||||
|             </property> | ||||
|            </widget> | ||||
|           </item> | ||||
| @ -1389,33 +1369,6 @@ 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"> | ||||
|               <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"> | ||||
|            <widget class="QComboBox" name="sound_output_channel_combo_box"> | ||||
|             <property name="toolTip"> | ||||
| @ -1446,16 +1399,63 @@ both here.</string> | ||||
|             </item> | ||||
|            </widget> | ||||
|           </item> | ||||
|           <item row="1" column="0"> | ||||
|            <widget class="QLabel" name="sound_output_label"> | ||||
|             <property name="text"> | ||||
|              <string>Ou&tput:</string> | ||||
|           <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="buddy"> | ||||
|              <cstring>sound_output_combo_box</cstring> | ||||
|             <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"> | ||||
|               <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> | ||||
|          </layout> | ||||
|         </widget> | ||||
|        </item> | ||||
| @ -1493,7 +1493,8 @@ both here.</string> | ||||
|              <bool>false</bool> | ||||
|             </property> | ||||
|             <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 name="text"> | ||||
|              <string>TextLabel</string> | ||||
| @ -1541,7 +1542,8 @@ both here.</string> | ||||
|              </sizepolicy> | ||||
|             </property> | ||||
|             <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 name="text"> | ||||
|              <string>TextLabel</string> | ||||
| @ -2949,14 +2951,20 @@ Right click for insert and delete options.</string> | ||||
|   <tabstop>use_dynamic_grid</tabstop> | ||||
|   <tabstop>region_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>DXCC_check_box</tabstop> | ||||
|   <tabstop>ppfx_check_box</tabstop> | ||||
|   <tabstop>font_push_button</tabstop> | ||||
|   <tabstop>decoded_text_font_push_button</tabstop> | ||||
|   <tabstop>monitor_off_check_box</tabstop> | ||||
|   <tabstop>monitor_last_used_check_box</tabstop> | ||||
|   <tabstop>quick_call_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>enable_VHF_features_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_two_stop_bit_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_none_radio_button</tabstop> | ||||
|   <tabstop>CAT_handshake_hardware_radio_button</tabstop> | ||||
|   <tabstop>force_DTR_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>opCallEntry</tabstop> | ||||
|   <tabstop>psk_reporter_check_box</tabstop> | ||||
|   <tabstop>psk_reporter_tcpip_check_box</tabstop> | ||||
|   <tabstop>udp_server_line_edit</tabstop> | ||||
|   <tabstop>udp_server_port_spin_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>highlighting_list_view</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_fetch_push_button</tabstop> | ||||
|   <tabstop>LotW_days_since_upload_spin_box</tabstop> | ||||
|   <tabstop>LotW_CSV_fetch_push_button</tabstop> | ||||
|   <tabstop>sbNtrials</tabstop> | ||||
|   <tabstop>sbAggressive</tabstop> | ||||
|   <tabstop>cbTwoPass</tabstop> | ||||
| @ -3039,13 +3052,18 @@ Right click for insert and delete options.</string> | ||||
|   <tabstop>sbTxDelay</tabstop> | ||||
|   <tabstop>cbx2ToneSpacing</tabstop> | ||||
|   <tabstop>cbx4ToneSpacing</tabstop> | ||||
|   <tabstop>rbLowSidelobes</tabstop> | ||||
|   <tabstop>rbMaxSensitivity</tabstop> | ||||
|   <tabstop>gbSpecialOpActivity</tabstop> | ||||
|   <tabstop>rbFox</tabstop> | ||||
|   <tabstop>rbHound</tabstop> | ||||
|   <tabstop>rbNA_VHF_Contest</tabstop> | ||||
|   <tabstop>rbEU_VHF_Contest</tabstop> | ||||
|   <tabstop>rbField_Day</tabstop> | ||||
|   <tabstop>Field_Day_Exchange</tabstop> | ||||
|   <tabstop>rbEU_VHF_Contest</tabstop> | ||||
|   <tabstop>rbRTTY_Roundup</tabstop> | ||||
|   <tabstop>RTTY_Exchange</tabstop> | ||||
|   <tabstop>rbWW_DIGI</tabstop> | ||||
|  </tabstops> | ||||
|  <resources/> | ||||
|  <connections> | ||||
| @ -3116,12 +3134,12 @@ Right click for insert and delete options.</string> | ||||
|  </connections> | ||||
|  <buttongroups> | ||||
|   <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="split_mode_button_group"/> | ||||
|   <buttongroup name="TX_mode_button_group"/> | ||||
|   <buttongroup name="TX_audio_source_button_group"/> | ||||
|   <buttongroup name="special_op_activity_button_group"/> | ||||
|   <buttongroup name="CAT_data_bits_button_group"/> | ||||
|   <buttongroup name="split_mode_button_group"/> | ||||
|   <buttongroup name="CAT_stop_bits_button_group"/> | ||||
|  </buttongroups> | ||||
| </ui> | ||||
|  | ||||
| @ -56,6 +56,7 @@ void Detector::clear () | ||||
| 
 | ||||
| qint64 Detector::writeData (char const * data, qint64 maxSize) | ||||
| { | ||||
|   //qDebug () << "Detector::writeData: size:" << maxSize;
 | ||||
|   static unsigned mstr0=999999; | ||||
|   qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; | ||||
|   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; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   return maxSize;    // we drop any data past the end of the buffer on
 | ||||
|   // the floor until the next period starts
 | ||||
|     // we drop any data past the end of the buffer on the floor until
 | ||||
|     // the next period starts
 | ||||
|     return maxSize; | ||||
| } | ||||
|  | ||||
							
								
								
									
										14
									
								
								INSTALL
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								INSTALL
									
									
									
									
									
								
							| @ -28,7 +28,7 @@ For MS  Windows see the section  "Building from Source on  MS Windows" | ||||
| below. For  Apple Mac see the  section "Building from Source  on Apple | ||||
| Mac". | ||||
| 
 | ||||
| Qt v5, preferably v5.5 or later is required to build WSJT-X. | ||||
| Qt v5, preferably v5.9 or later is required to build WSJT-X. | ||||
| 
 | ||||
| Qt v5  multimedia support, serial  port, and Linguist is  necessary as | ||||
| well  as  the  core  Qt  v5 components,  normally  installing  the  Qt | ||||
| @ -43,8 +43,8 @@ the  libfftw library  development  package.   Normally installing  the | ||||
| library  development  package  pulls  in all  the  FFTW  v3  libraries | ||||
| including the single precision variant. | ||||
| 
 | ||||
| The Hamlib library optionally requires  the libusb-1.0 library, if the | ||||
| development   version  (libusb-1.0-dev)   is  available   Hamlib  will | ||||
| The Hamlib  library optionally  requires the libusb-1.0-1  library, if | ||||
| the development  version (libusb-1.0-0-dev)  is available  Hamlib will | ||||
| configure its  custom USB device  back end  drivers. Most rigs  do not | ||||
| require this so normally you  can choose not to install libusb-1.0-dev | ||||
| but if you have  a SoftRock USB or similar SDR that  uses a custom USB | ||||
| @ -89,7 +89,8 @@ $ git clone git://git.code.sf.net/p/wsjt/wsjtx src | ||||
| To build WSJT-X you will need CMake and asciidoc installed. | ||||
| 
 | ||||
| $ cd ~/wsjtx-prefix/build | ||||
| $ cmake -D CMAKE_PREFIX_PATH=~/hamlib-prefix ../src | ||||
| $ cmake -D CMAKE_PREFIX_PATH=~/hamlib-prefix -DWSJT_SKIP_MANPAGES=ON \ | ||||
|   	-DWSJT_GENERATE_DOCS=OFF ../src | ||||
| $ cmake --build . | ||||
| $ cmake --build . --target install | ||||
| 
 | ||||
| @ -99,7 +100,8 @@ configure step like: | ||||
| 
 | ||||
| $ cd ~/wsjtx-prefix/build | ||||
| $ cmake -D CMAKE_PREFIX_PATH=~/hamlib-prefix \ | ||||
|    -D CMAKE_INSTALL_PREFIX=~/wsjtx-prefix ../src | ||||
|     -DWSJT_SKIP_MANPAGES=ON -DWSJT_GENERATE_DOCS=OFF \ | ||||
|     -D CMAKE_INSTALL_PREFIX=~/wsjtx-prefix ../src | ||||
| $ cmake --build . | ||||
| $ cmake --build . --target install | ||||
| 
 | ||||
| @ -316,7 +318,7 @@ configure: | ||||
| $ cd ~/wsjtx-prefix/build | ||||
| $ FC=gfortran-mp-5 \ | ||||
|    cmake \ | ||||
|    -D CMAKE_PREFIX_PATH="~/Qt/5.7/clang_64;~/hamlib-prefix;/opt/local" \ | ||||
|    -D CMAKE_PREFIX_PATH="~/Qt/5.9/clang_64;~/hamlib-prefix;/opt/local" \ | ||||
|    -D CMAKE_INSTALL_PREFIX=~/wsjtx-prefix \ | ||||
|    -D CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk \ | ||||
|    ~/wsjtx-prefix/src | ||||
|  | ||||
| @ -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;
 | ||||
| 
 | ||||
|   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) | ||||
| @ -172,15 +179,12 @@ qint64 Modulator::readData (char * data, qint64 maxSize) | ||||
|             { | ||||
|               samples = load (0, samples); // silence
 | ||||
|             } while (--m_silentFrames && samples != end); | ||||
|           qDebug () << "played:" << framesGenerated << "silent frames"; | ||||
|           if (!m_silentFrames) | ||||
|             { | ||||
|               Q_EMIT stateChanged ((m_state = Active)); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         // qDebug() << "m_silentFrames:" << m_silentFrames << "m_ic:" << m_ic << "m_state:" << m_state;
 | ||||
| 
 | ||||
|         m_cwLevel = false; | ||||
|         m_ramp = 0;		// prepare for CW wave shaping
 | ||||
|       } | ||||
|  | ||||
| @ -465,7 +465,11 @@ void MessageClient::set_server (QString const& server) | ||||
|     { | ||||
|       // queue a host address lookup
 | ||||
|       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); | ||||
| #else | ||||
|       m_->dns_lookup_id_ = QHostInfo::lookupHost (server, &*m_, SLOT (host_info_results (QHostInfo))); | ||||
| #endif | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -65,7 +65,6 @@ public: | ||||
| 
 | ||||
|     // This timer sets the interval to check for spots to send.
 | ||||
|     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
 | ||||
|     // information if we are using UDP, in case server has been
 | ||||
| @ -80,7 +79,6 @@ public: | ||||
|                                                          send_receiver_data_ = 3; // three times
 | ||||
|                                                        } | ||||
|                                                    }); | ||||
|     descriptor_timer_.start (1 * 60 * 60 * 1000); // hourly
 | ||||
|   } | ||||
| 
 | ||||
|   void check_connection () | ||||
| @ -156,6 +154,25 @@ public: | ||||
|     // use this for pseudo connection with UDP, allows us to use
 | ||||
|     // QIODevice::write() instead of QUDPSocket::writeDatagram()
 | ||||
|     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); | ||||
| @ -402,7 +419,13 @@ void PSKReporter::impl::send_report (bool send_residue) | ||||
|               writeUtfString (tx_out, spot.grid_); | ||||
|               tx_out | ||||
|                 << 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 (); | ||||
| @ -429,7 +452,13 @@ void PSKReporter::impl::send_report (bool send_residue) | ||||
|               // insert Length and Export Time
 | ||||
|               set_length (message, payload_); | ||||
|               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
 | ||||
|               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) | ||||
| { | ||||
|   m_->check_connection (); | ||||
|   if (call != m_->rx_call_ || gridSquare != m_->rx_grid_ || antenna != m_->rx_ant_) | ||||
|     { | ||||
|       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 | ||||
|                                      , QString const& mode, int snr) | ||||
| { | ||||
|   m_->check_connection (); | ||||
|   if (m_->socket_ && m_->socket_->isValid ()) | ||||
|     { | ||||
|       if (QAbstractSocket::UnconnectedState == m_->socket_->state ()) | ||||
| @ -490,7 +521,14 @@ bool PSKReporter::addRemoteStation (QString const& call, QString const& grid, Ra | ||||
|   return false; | ||||
| } | ||||
| 
 | ||||
| void PSKReporter::sendReport () | ||||
| void PSKReporter::sendReport (bool last) | ||||
| { | ||||
|   m_->send_report (true); | ||||
|   if (m_->socket_ && QAbstractSocket::ConnectedState == m_->socket_->state ()) | ||||
|     { | ||||
|       m_->send_report (true); | ||||
|     } | ||||
|   if (last) | ||||
|     { | ||||
|       m_->stop (); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -29,7 +29,7 @@ public: | ||||
|   //
 | ||||
|   // Flush any pending spots to PSK Reporter
 | ||||
|   //
 | ||||
|   void sendReport (); | ||||
|   void sendReport (bool last = false); | ||||
| 
 | ||||
|   Q_SIGNAL void errorOccurred (QString const& reason); | ||||
| 
 | ||||
|  | ||||
| @ -220,7 +220,7 @@ public: | ||||
|     , carry_ {false} | ||||
|     , seed_ {{rand (), rand (), rand (), rand (), rand (), rand (), rand (), rand ()}} | ||||
|     , gen_ {seed_} | ||||
|     , dist_ {1, 100} | ||||
|     , dist_ {0, 99} | ||||
|   { | ||||
|     auto num_bands = configuration_->bands ()->rowCount (); | ||||
|     for (auto& flags : bands_) | ||||
|  | ||||
| @ -41,7 +41,11 @@ sudo dpkg -P wsjtx | ||||
| You may also need to execute the following command in a terminal: | ||||
| 
 | ||||
| [example] | ||||
| sudo apt install libqt5multimedia5-plugins libqt5serialport5 libqt5sql5-sqlite libfftw3-single3 | ||||
| .... | ||||
| sudo apt install libgfortran5 libqt5widgets5 libqt5network5 \ | ||||
|      libqt5printsupport5 libqt5multimedia5-plugins libqt5serialport5 \ | ||||
|      libqt5sql5-sqlite libfftw3-single3 libgomp1 libusb-1.0-0 | ||||
| .... | ||||
| 
 | ||||
| Fedora, CentOS, Red Hat, and other rpm-based systems: | ||||
| 
 | ||||
| @ -70,4 +74,8 @@ sudo rpm -e wsjtx | ||||
| You may also need to execute the following command in a terminal: | ||||
| 
 | ||||
| [example] | ||||
| sudo dnf install fftw-libs-single qt5-qtmultimedia qt5-qtserialport  | ||||
| .... | ||||
| sudo dnf install libgfortran fftw-libs-single qt5-qtbase \ | ||||
|      qt5-qtmultimedia qt5-qtserialport qt5-qtsvg \ | ||||
|      qt5-qtserialport libgomp libusbx | ||||
| .... | ||||
|  | ||||
| @ -216,7 +216,7 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) | ||||
|   character*38 c | ||||
|   character*36 a2 | ||||
|   integer hashmy10,hashmy12,hashmy22,hashdx10,hashdx12,hashdx22 | ||||
|   logical unpk28_success,unpk77_success | ||||
|   logical unpk28_success,unpk77_success,unpkg4_success | ||||
|   logical dxcall13_set,mycall13_set | ||||
| 
 | ||||
|   data a2/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'/,nzzz/46656/ | ||||
| @ -364,10 +364,11 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) | ||||
|         idbm=nint(idbm*10.0/3.0) | ||||
|         call unpack28(n28,call_1,unpk28_success)  | ||||
|         if(.not.unpk28_success) unpk77_success=.false. | ||||
|         call to_grid4(igrid4,grid4) | ||||
|         call to_grid4(igrid4,grid4,unpkg4_success) | ||||
|         if(.not.unpkg4_success) unpk77_success=.false. | ||||
|         write(crpt,'(i3)') idbm | ||||
|         msg=trim(call_1)//' '//grid4//' '//trim(adjustl(crpt)) | ||||
|         call save_hash_call(call_1,n10,n12,n22)    !### Is this OK here? ### | ||||
|         if (unpk77_success) call save_hash_call(call_1,n10,n12,n22) !### Is this OK here? ### | ||||
| 
 | ||||
|      else if(itype.eq.2) then | ||||
| ! WSPR Type 2 | ||||
| @ -417,10 +418,9 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) | ||||
|         n28=n22+2063592 | ||||
|         call unpack28(n28,call_1,unpk28_success)  | ||||
|         if(.not.unpk28_success) unpk77_success=.false. | ||||
|         call to_grid(igrid6,grid6) | ||||
|         call to_grid(igrid6,grid6,unpkg4_success) | ||||
|         if(.not.unpkg4_success) unpk77_success=.false. | ||||
|         msg=trim(call_1)//' '//grid6 | ||||
| 
 | ||||
| 
 | ||||
|      endif | ||||
|    | ||||
|   else if(i3.eq.0 .and. n3.gt.6) then | ||||
| @ -452,7 +452,8 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) | ||||
|         if(i.ge.4) call add_call_to_recent_calls(call_2) | ||||
|      endif | ||||
|      if(igrid4.le.MAXGRID4) then | ||||
|         call to_grid4(igrid4,grid4) | ||||
|         call to_grid4(igrid4,grid4,unpkg4_success) | ||||
|         if(.not.unpkg4_success) unpk77_success=.false. | ||||
|         if(ir.eq.0) msg=trim(call_1)//' '//trim(call_2)//' '//grid4 | ||||
|         if(ir.eq.1) msg=trim(call_1)//' '//trim(call_2)//' R '//grid4 | ||||
|         if(msg(1:3).eq.'CQ ' .and. ir.eq.1) unpk77_success=.false. | ||||
| @ -569,7 +570,7 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) | ||||
|      nrs=52+irpt | ||||
|      write(cexch,1022) nrs,iserial | ||||
| 1022 format(i2,i4.4) | ||||
|      call to_grid6(igrid6,grid6) | ||||
|      call to_grid6(igrid6,grid6,unpk77_success) | ||||
|      if(ir.eq.0) msg=trim(call_1)//' '//trim(call_2)//' '//cexch//' '//grid6 | ||||
|      if(ir.eq.1) msg=trim(call_1)//' '//trim(call_2)//' R '//cexch//' '//grid6 | ||||
| 
 | ||||
| @ -1499,60 +1500,84 @@ subroutine add_call_to_recent_calls(callsign) | ||||
|   return | ||||
| end subroutine add_call_to_recent_calls | ||||
| 
 | ||||
| subroutine to_grid4(n,grid4) | ||||
| subroutine to_grid4(n,grid4,ok) | ||||
|   character*4 grid4 | ||||
|    | ||||
|   logical ok | ||||
| 
 | ||||
|   ok=.false. | ||||
|   j1=n/(18*10*10) | ||||
|   if (j1.lt.0.or.j1.gt.17) goto 900 | ||||
|   n=n-j1*18*10*10 | ||||
|   j2=n/(10*10) | ||||
|   if (j2.lt.0.or.j2.gt.17) goto 900 | ||||
|   n=n-j2*10*10 | ||||
|   j3=n/10 | ||||
|   if (j3.lt.0.or.j3.gt.9) goto 900 | ||||
|   j4=n-j3*10 | ||||
|   if (j4.lt.0.or.j4.gt.9) goto 900 | ||||
|   grid4(1:1)=char(j1+ichar('A')) | ||||
|   grid4(2:2)=char(j2+ichar('A')) | ||||
|   grid4(3:3)=char(j3+ichar('0')) | ||||
|   grid4(4:4)=char(j4+ichar('0')) | ||||
|    | ||||
|   return | ||||
|   ok=.true. | ||||
| 
 | ||||
| 900 return | ||||
| end subroutine to_grid4 | ||||
| 
 | ||||
| subroutine to_grid6(n,grid6) | ||||
| subroutine to_grid6(n,grid6,ok) | ||||
|   character*6 grid6 | ||||
|   logical ok | ||||
| 
 | ||||
|   ok=.false. | ||||
|   j1=n/(18*10*10*24*24) | ||||
|   if (j1.lt.0.or.j1.gt.17) goto 900 | ||||
|   n=n-j1*18*10*10*24*24 | ||||
|   j2=n/(10*10*24*24) | ||||
|   if (j2.lt.0.or.j2.gt.17) goto 900 | ||||
|   n=n-j2*10*10*24*24 | ||||
|   j3=n/(10*24*24) | ||||
|   if (j3.lt.0.or.j3.gt.9) goto 900 | ||||
|   n=n-j3*10*24*24 | ||||
|   j4=n/(24*24) | ||||
|   if (j4.lt.0.or.j4.gt.9) goto 900 | ||||
|   n=n-j4*24*24 | ||||
|   j5=n/24 | ||||
|   if (j5.lt.0.or.j5.gt.23) goto 900 | ||||
|   j6=n-j5*24 | ||||
|   if (j6.lt.0.or.j6.gt.23) goto 900 | ||||
|   grid6(1:1)=char(j1+ichar('A')) | ||||
|   grid6(2:2)=char(j2+ichar('A')) | ||||
|   grid6(3:3)=char(j3+ichar('0')) | ||||
|   grid6(4:4)=char(j4+ichar('0')) | ||||
|   grid6(5:5)=char(j5+ichar('A')) | ||||
|   grid6(6:6)=char(j6+ichar('A'))   | ||||
|   ok=.true. | ||||
| 
 | ||||
|   return | ||||
| 900 return | ||||
| end subroutine to_grid6 | ||||
| 
 | ||||
| subroutine to_grid(n,grid6) | ||||
| subroutine to_grid(n,grid6,ok) | ||||
|   ! 4-, or 6-character grid | ||||
|   character*6 grid6 | ||||
|   logical ok | ||||
| 
 | ||||
|   ok=.false. | ||||
|   j1=n/(18*10*10*25*25) | ||||
|   if (j1.lt.0.or.j1.gt.17) goto 900 | ||||
|   n=n-j1*18*10*10*25*25 | ||||
|   j2=n/(10*10*25*25) | ||||
|   if (j2.lt.0.or.j2.gt.17) goto 900 | ||||
|   n=n-j2*10*10*25*25 | ||||
|   j3=n/(10*25*25) | ||||
|   if (j3.lt.0.or.j3.gt.9) goto 900 | ||||
|   n=n-j3*10*25*25 | ||||
|   j4=n/(25*25) | ||||
|   if (j4.lt.0.or.j4.gt.9) goto 900 | ||||
|   n=n-j4*25*25 | ||||
|   j5=n/25 | ||||
|   if (j5.lt.0.or.j5.gt.24) goto 900 | ||||
|   j6=n-j5*25 | ||||
|   if (j6.lt.0.or.j6.gt.24) goto 900 | ||||
|   grid6='' | ||||
|   grid6(1:1)=char(j1+ichar('A')) | ||||
|   grid6(2:2)=char(j2+ichar('A')) | ||||
| @ -1562,8 +1587,9 @@ subroutine to_grid(n,grid6) | ||||
|      grid6(5:5)=char(j5+ichar('A')) | ||||
|      grid6(6:6)=char(j6+ichar('A')) | ||||
|   endif | ||||
|   ok=.true. | ||||
| 
 | ||||
|   return | ||||
| 900 return | ||||
| end subroutine to_grid | ||||
| 
 | ||||
| end module packjt77 | ||||
|  | ||||
| @ -208,7 +208,6 @@ subroutine multimode_decoder(ss,id2,params,nfsample) | ||||
| ! We're in FST4 mode | ||||
|      ndepth=iand(params%ndepth,3) | ||||
|      iwspr=0 | ||||
|      if(iand(params%ndepth,128).ne.0) iwspr=2 | ||||
|      call timer('dec240  ',0) | ||||
|      call my_fst4%decode(fst4_decoded,id2,params%nutc,                    & | ||||
|           params%nQSOProgress,params%nfqso,params%nfa,params%nfb,         & | ||||
|  | ||||
| @ -319,12 +319,12 @@ AD1CCty::AD1CCty (Configuration const * configuration) | ||||
| { | ||||
|   Q_ASSERT (configuration); | ||||
|   // 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.
 | ||||
|   QDir dataPath {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}; | ||||
|   m_->path_ = dataPath.exists (file_name) | ||||
|     ? 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_}; | ||||
|   if (file.open (QFile::ReadOnly)) | ||||
|     { | ||||
|  | ||||
							
								
								
									
										2
									
								
								main.cpp
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								main.cpp
									
									
									
									
									
								
							| @ -97,7 +97,7 @@ namespace | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|   // ### Add timestamps to all debug messages
 | ||||
| //  qSetMessagePattern ("[%{time yyyyMMdd HH:mm:ss.zzz t} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{message}");
 | ||||
|   // qSetMessagePattern ("[%{time yyyyMMdd HH:mm:ss.zzz t} %{if-debug}D%{endif}%{if-info}I%{endif}%{if-warning}W%{endif}%{if-critical}C%{endif}%{if-fatal}F%{endif}] %{message}");
 | ||||
| 
 | ||||
|   init_random_seed (); | ||||
| 
 | ||||
|  | ||||
| @ -15,14 +15,14 @@ namespace | ||||
|     Radio::Frequency lower_bound_; | ||||
|     Radio::Frequency upper_bound_; | ||||
|   } constexpr ADIF_bands[] = { | ||||
|     {"2190m",	136000u,  		137000u}, | ||||
|     {"2190m",	135700u,  		137800u}, | ||||
|     {"630m",  472000u,  		479000u}, | ||||
|     {"560m",  501000u,  		504000u}, | ||||
|     {"160m",  1800000u,   	2000000u}, | ||||
|     {"80m",   3500000u,   	4000000u}, | ||||
|     {"60m",   5060000u,   	5450000u}, | ||||
|     {"40m",   7000000u,   	7300000u}, | ||||
|     {"30m",   10000000u,  	10150000u}, | ||||
|     {"30m",   10100000u,  	10150000u}, | ||||
|     {"20m",   14000000u,  	14350000u}, | ||||
|     {"17m",   18068000u,  	18168000u}, | ||||
|     {"15m",   21000000u,  	21450000u}, | ||||
|  | ||||
| @ -37,14 +37,14 @@ void update_dynamic_property (QWidget * widget, char const * property, QVariant | ||||
|   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; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| } | ||||
|  | ||||
| @ -69,11 +69,11 @@ QString font_as_stylesheet (QFont const&); | ||||
| // conditional style sheet updates
 | ||||
| void update_dynamic_property (QWidget *, char const * property, QVariant const& value); | ||||
| 
 | ||||
| // round a QDateTime instance to an interval
 | ||||
| QDateTime qt_round_date_time_to (QDateTime dt, int seconds); | ||||
| // round a QDateTime instance to an integral interval of milliseconds
 | ||||
| QDateTime qt_round_date_time_to (QDateTime dt, int milliseconds); | ||||
| 
 | ||||
| // truncate a QDateTime to an interval
 | ||||
| QDateTime qt_truncate_date_time_to (QDateTime dt, int seconds); | ||||
| // truncate a QDateTime to an integral interval of milliseconds
 | ||||
| QDateTime qt_truncate_date_time_to (QDateTime dt, int milliseconds); | ||||
| 
 | ||||
| template <class T> | ||||
| class VPtr | ||||
|  | ||||
							
								
								
									
										23
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								tests/CMakeLists.txt
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										138
									
								
								tests/test_qt_helpers.cpp
									
									
									
									
									
										Normal 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" | ||||
| @ -210,6 +210,8 @@ namespace | ||||
|   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 (); | ||||
|   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) | ||||
|   { | ||||
| @ -284,7 +286,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|   m_idleMinutes {0}, | ||||
|   m_nSubMode {0}, | ||||
|   m_nclearave {1}, | ||||
|   m_pctx {0}, | ||||
|   m_nseq {0}, | ||||
|   m_nWSPRdecodes {0}, | ||||
|   m_k0 {9999999}, | ||||
| @ -310,7 +311,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|   m_bShMsgs {false}, | ||||
|   m_bSWL {false}, | ||||
|   m_uploading {false}, | ||||
|   m_txNext {false}, | ||||
|   m_grid6 {false}, | ||||
|   m_tuneup {false}, | ||||
|   m_bTxTime {false}, | ||||
| @ -395,8 +395,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|       }, | ||||
|   m_sfx {"P",  "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",  "9",  "A"}, | ||||
|   mem_jt9 {shdmem}, | ||||
|   m_msAudioOutputBuffered (0u), | ||||
|   m_framesAudioInputBuffered (RX_SAMPLE_RATE / 10), | ||||
|   m_downSampleFactor (downSampleFactor), | ||||
|   m_audioThreadPriority (QThread::HighPriority), | ||||
|   m_bandEdited {false}, | ||||
| @ -472,9 +470,23 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|   connect (this, &MainWindow::startAudioInputStream, m_soundInput, &SoundInput::start); | ||||
|   connect (this, &MainWindow::suspendAudioInputStream, m_soundInput, &SoundInput::suspend); | ||||
|   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(m_soundInput, &SoundInput::error, this, &MainWindow::showSoundInError); | ||||
|   // 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 (this, &MainWindow::finished, this, &MainWindow::close); | ||||
| @ -939,14 +951,24 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|   connect (&m_wav_future_watcher, &QFutureWatcher<void>::finished, this, &MainWindow::diskDat); | ||||
| 
 | ||||
|   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 ()); | ||||
|   Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered); | ||||
|   if (!m_config.audio_input_device ().isNull ()) | ||||
|     { | ||||
|       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); | ||||
| 
 | ||||
|   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_10->setStyleSheet("QLabel{background-color: #aabec8}"); | ||||
|   ui->label_9->setStyleSheet("QLabel{color: #000000; 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
 | ||||
|   // to turn off split on the rig e.g. WSPR
 | ||||
| @ -974,7 +996,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|   } | ||||
|   m_saveDecoded=ui->actionSave_decoded->isChecked(); | ||||
|   m_saveAll=ui->actionSave_all->isChecked(); | ||||
|   ui->sbTxPercent->setValue(m_pctx); | ||||
|   ui->TxPowerComboBox->setCurrentIndex(int(.3 * m_dBm + .2)); | ||||
|   ui->cbUploadWSPR_Spots->setChecked(m_uploadWSPRSpots); | ||||
|   if((m_ndepth&7)==1) ui->actionQuickDecode->setChecked(true); | ||||
| @ -997,12 +1018,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, | ||||
|   m_isort=-3; | ||||
|   m_max_dB=70; | ||||
|   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(); | ||||
|   VHF_features_enabled(m_config.enable_VHF_features()); | ||||
|   m_wideGraph->setVHF(m_config.enable_VHF_features()); | ||||
| @ -1146,7 +1161,7 @@ void MainWindow::writeSettings() | ||||
|   m_settings->setValue("GUItab",ui->tabWidget->currentIndex()); | ||||
|   m_settings->setValue("OutBufSize",outBufSize); | ||||
|   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("RR73",m_send_RR73); | ||||
|   m_settings->setValue ("WSPRPreferType1", ui->WSPR_prefer_type_1_check_box->isChecked ()); | ||||
| @ -1237,7 +1252,8 @@ void MainWindow::readSettings() | ||||
|   ui->TxFreqSpinBox->setValue(0); // ensure a change is signaled
 | ||||
|   ui->TxFreqSpinBox->setValue(m_settings->value("TxFreq",1500).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_send_RR73=m_settings->value("RR73",false).toBool(); | ||||
|   if(m_send_RR73) { | ||||
| @ -1246,7 +1262,6 @@ void MainWindow::readSettings() | ||||
|   } | ||||
|   ui->WSPR_prefer_type_1_check_box->setChecked (m_settings->value ("WSPRPreferType1", true).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->band_hopping_group_box->setChecked (m_settings->value ("BandHopping", false).toBool()); | ||||
|   // setup initial value of tx attenuator
 | ||||
| @ -1279,8 +1294,6 @@ void MainWindow::readSettings() | ||||
|   // use these initialisation settings to tune the audio o/p buffer
 | ||||
|   // size and audio thread priority
 | ||||
|   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_settings->endGroup (); | ||||
| 
 | ||||
| @ -1545,6 +1558,10 @@ void MainWindow::dataSink(qint64 frames) | ||||
|     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_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")) { | ||||
|       //Always save unless "Save None"; may delete later
 | ||||
|       if(m_TRperiod < 60) { | ||||
| @ -1623,14 +1640,15 @@ QString MainWindow::save_wave_file (QString const& name, short const * data, int | ||||
|   format.setChannelCount (1); | ||||
|   format.setSampleSize (16); | ||||
|   format.setSampleType (QAudioFormat::SignedInt); | ||||
|   auto source = QString {"%1, %2"}.arg (my_callsign).arg (my_grid); | ||||
|   auto comment = QString {"Mode=%1%2, Freq=%3%4"} | ||||
|      .arg (mode) | ||||
|      .arg (QString {(mode.contains ('J') && !mode.contains ('+')) || mode.startsWith ("FST4") | ||||
|            ? QString {", Sub Mode="} + QChar {'A' + sub_mode} | ||||
|          : QString {}}) | ||||
|         .arg (Radio::frequency_MHz_string (frequency)) | ||||
|      .arg (QString {mode!="WSPR" ? QString {", DXCall=%1, DXGrid=%2"} | ||||
|   auto source = QString {"%1; %2"}.arg (my_callsign).arg (my_grid); | ||||
|   auto comment = QString {"Mode=%1%2; Freq=%3%4"} | ||||
|                    .arg (mode) | ||||
|                    .arg (QString {(mode.contains ('J') && !mode.contains ('+')) | ||||
|                          || mode.startsWith ("FST4") || mode.startsWith ("QRA") | ||||
|                          ? QString {"; Sub Mode="} + QString::number (int (samples / 12000)) + QChar {'A' + sub_mode} | ||||
|                        : QString {}}) | ||||
|                    .arg (Radio::frequency_MHz_string (frequency)) | ||||
|                    .arg (QString {mode!="WSPR" ? QString {"; DXCall=%1; DXGrid=%2"} | ||||
|          .arg (his_call) | ||||
|          .arg (his_grid).toLocal8Bit () : ""}); | ||||
|   BWFFile::InfoDictionary list_info { | ||||
| @ -1792,6 +1810,7 @@ void MainWindow::on_actionSettings_triggered()               //Setup Dialog | ||||
|   auto callsign = m_config.my_callsign (); | ||||
|   auto my_grid = m_config.my_grid (); | ||||
|   SpecOp nContest0=m_config.special_op_id(); | ||||
|   auto psk_on = m_config.spot_to_psk_reporter (); | ||||
|   if (QDialog::Accepted == m_config.exec ()) { | ||||
|     checkMSK144ContestType(); | ||||
|     if (m_config.my_callsign () != callsign) { | ||||
| @ -1805,18 +1824,25 @@ void MainWindow::on_actionSettings_triggered()               //Setup Dialog | ||||
|     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
 | ||||
| 
 | ||||
|     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 ()) { | ||||
|       Q_EMIT startAudioInputStream (m_config.audio_input_device (), | ||||
|                  m_framesAudioInputBuffered, m_detector, m_downSampleFactor, | ||||
|                                       m_config.audio_input_channel ()); | ||||
|       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.restart_audio_output ()) { | ||||
|       Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), | ||||
|            AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, | ||||
|                                           m_msAudioOutputBuffered); | ||||
|       Q_EMIT initializeAudioOutputStream (m_config.audio_output_device () | ||||
|                                           , AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2 | ||||
|                                           , tx_audio_buffer_size); | ||||
|     } | ||||
| 
 | ||||
|     displayDialFrequency (); | ||||
| @ -1918,18 +1944,14 @@ void MainWindow::on_autoButton_clicked (bool checked) | ||||
|     m_nclearave=1; | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| void MainWindow::on_sbTxPercent_valueChanged (int n) | ||||
| { | ||||
|   update_dynamic_property (ui->sbTxPercent, "notx", !n); | ||||
| } | ||||
| 
 | ||||
| void MainWindow::auto_tx_mode (bool state) | ||||
| { | ||||
|   ui->autoButton->setChecked (state); | ||||
| @ -2288,8 +2310,8 @@ bool MainWindow::eventFilter (QObject * object, QEvent * event) | ||||
| void MainWindow::createStatusBar()                           //createStatusBar
 | ||||
| { | ||||
|   tx_status_label.setAlignment (Qt::AlignHCenter); | ||||
|   tx_status_label.setMinimumSize (QSize  {150, 18}); | ||||
|   tx_status_label.setStyleSheet ("QLabel{background-color: #00ff00}"); | ||||
|   tx_status_label.setMinimumSize (QSize  {100, 18}); | ||||
|   tx_status_label.setStyleSheet ("QLabel{color: #000000; background-color: #00ff00}"); | ||||
|   tx_status_label.setFrameStyle (QFrame::Panel | QFrame::Sunken); | ||||
|   statusBar()->addWidget (&tx_status_label); | ||||
| 
 | ||||
| @ -2337,39 +2359,39 @@ void MainWindow::setup_status_bar (bool vhf) | ||||
|       mode_label.setText (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) { | ||||
|     mode_label.setStyleSheet ("QLabel{background-color: #ff6ec7}"); | ||||
|     mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff6ec7}"); | ||||
|   } 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) { | ||||
|     mode_label.setStyleSheet ("QLabel{background-color: #66ffff}"); | ||||
|     mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #66ffff}"); | ||||
|   } 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) { | ||||
|     mode_label.setStyleSheet ("QLabel{background-color: #66ff66}"); | ||||
|     mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #66ff66}"); | ||||
|   } else if ("QRA64" == m_mode) { | ||||
|     mode_label.setStyleSheet ("QLabel{background-color: #99ff33}"); | ||||
|     mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff33}"); | ||||
|   } else if ("QRA66" == m_mode) { | ||||
|     mode_label.setStyleSheet ("QLabel{background-color: #99ff33}"); | ||||
|     mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff33}"); | ||||
|   } 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) { | ||||
|     mode_label.setStyleSheet ("QLabel{background-color: #ff0099}"); | ||||
|     mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff0099}"); | ||||
|   } 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) { | ||||
|     mode_label.setStyleSheet ("QLabel{background-color: #99ff66}"); | ||||
|     mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff66}"); | ||||
|   } 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) { | ||||
|     mode_label.setStyleSheet ("QLabel{background-color: #ff9933}"); | ||||
|     mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff9933}"); | ||||
|   } | ||||
|   last_tx_label.setText (QString {}); | ||||
|   if (m_mode.contains (QRegularExpression {R"(^(Echo|ISCAT))"})) { | ||||
|     if (band_hopping_label.isVisible ()) statusBar ()->removeWidget (&band_hopping_label); | ||||
|   } 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 ()) { | ||||
|       statusBar ()->addWidget (&band_hopping_label); | ||||
|       band_hopping_label.show (); | ||||
| @ -2700,7 +2722,7 @@ void MainWindow::on_actionOpen_triggered()                     //Open File | ||||
|     m_path=fname; | ||||
|     int i1=fname.lastIndexOf("/"); | ||||
|     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 + " "); | ||||
|     on_stopButton_clicked(); | ||||
|     m_diskData=true; | ||||
| @ -2780,7 +2802,7 @@ void MainWindow::on_actionOpen_next_in_directory_triggered()   //Open Next | ||||
|       m_path=fname; | ||||
|       int i1=fname.lastIndexOf("/"); | ||||
|       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 + " "); | ||||
|       m_diskData=true; | ||||
|       read_wav_file (fname); | ||||
| @ -2933,7 +2955,7 @@ void MainWindow::on_actionSpecial_mouse_commands_triggered() | ||||
|     <td><b>Click</b> to set Rx frequency.<br/> | ||||
|         <b>Shift-click</b> to set Tx frequency.<br/> | ||||
|         <b>Ctrl-click</b> or <b>Right-click</b> to set Rx and Tx frequencies.<br/> | ||||
| 	<b>Double-click</b> to also decode at Rx frequency.<br/> | ||||
|         <b>Double-click</b> to also decode at Rx frequency.<br/> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
| @ -2941,10 +2963,10 @@ void MainWindow::on_actionSpecial_mouse_commands_triggered() | ||||
|     <td><b>Double-click</b> to copy second callsign to Dx Call,<br/> | ||||
|         locator to Dx Grid, change Rx and Tx frequency to<br/> | ||||
|         decoded signal's frequency, and generate standard<br/> | ||||
| 	messages.<br/> | ||||
| 	If <b>Hold Tx Freq</b> is checked or first callsign in message<br/> | ||||
| 	is your own call, Tx frequency is not changed unless <br/> | ||||
| 	<b>Ctrl</b> is held down.<br/> | ||||
|         messages.<br/> | ||||
|         If <b>Hold Tx Freq</b> is checked or first callsign in message<br/> | ||||
|         is your own call, Tx frequency is not changed unless <br/> | ||||
|         <b>Ctrl</b> is held down.<br/> | ||||
|     </td> | ||||
|   </tr> | ||||
|   <tr> | ||||
| @ -3122,56 +3144,58 @@ void MainWindow::decode()                                       //decode() | ||||
|   //newdat=1  ==> this is new data, must do the big FFT
 | ||||
|   //nagain=1  ==> decode only at fQSO +/- Tol
 | ||||
| 
 | ||||
|   char *to = (char*)mem_jt9->data(); | ||||
|   char *from = (char*) dec_data.ipc; | ||||
|   int size=sizeof(struct dec_data); | ||||
|   if(dec_data.params.newdat==0) { | ||||
|     int noffset {offsetof (struct dec_data, params.nutc)}; | ||||
|     to += noffset; | ||||
|     from += noffset; | ||||
|     size -= noffset; | ||||
|   } | ||||
|   if(m_mode=="ISCAT" or m_mode=="MSK144" or m_bFast9) { | ||||
|     float t0=m_t0; | ||||
|     float t1=m_t1; | ||||
|     qApp->processEvents();                                //Update the waterfall
 | ||||
|     if(m_nPick > 0) { | ||||
|       t0=m_t0Pick; | ||||
|       t1=m_t1Pick; | ||||
|   if (auto * to = reinterpret_cast<char *> (mem_jt9->data())) | ||||
|     { | ||||
|       char *from = (char*) dec_data.ipc; | ||||
|       int size=sizeof(struct dec_data); | ||||
|       if(dec_data.params.newdat==0) { | ||||
|         int noffset {offsetof (struct dec_data, params.nutc)}; | ||||
|         to += noffset; | ||||
|         from += noffset; | ||||
|         size -= noffset; | ||||
|       } | ||||
|       if(m_mode=="ISCAT" or m_mode=="MSK144" or m_bFast9) { | ||||
|         float t0=m_t0; | ||||
|         float t1=m_t1; | ||||
|         qApp->processEvents();                                //Update the waterfall
 | ||||
|         if(m_nPick > 0) { | ||||
|           t0=m_t0Pick; | ||||
|           t1=m_t1Pick; | ||||
|         } | ||||
|         static short int d2b[360000]; | ||||
|         narg[0]=dec_data.params.nutc; | ||||
|         if(m_kdone>int(12000.0*m_TRperiod)) { | ||||
|           m_kdone=int(12000.0*m_TRperiod); | ||||
|         } | ||||
|         narg[1]=m_kdone; | ||||
|         narg[2]=m_nSubMode; | ||||
|         narg[3]=dec_data.params.newdat; | ||||
|         narg[4]=dec_data.params.minSync; | ||||
|         narg[5]=m_nPick; | ||||
|         narg[6]=1000.0*t0; | ||||
|         narg[7]=1000.0*t1; | ||||
|         narg[8]=2;                                //Max decode lines per decode attempt
 | ||||
|         if(dec_data.params.minSync<0) narg[8]=50; | ||||
|         if(m_mode=="ISCAT") narg[9]=101;          //ISCAT
 | ||||
|         if(m_mode=="JT9") narg[9]=102;            //Fast JT9
 | ||||
|         if(m_mode=="MSK144") narg[9]=104;         //MSK144
 | ||||
|         narg[10]=ui->RxFreqSpinBox->value(); | ||||
|         narg[11]=ui->sbFtol->value (); | ||||
|         narg[12]=0; | ||||
|         narg[13]=-1; | ||||
|         narg[14]=m_config.aggressive(); | ||||
|         memcpy(d2b,dec_data.d2,2*360000); | ||||
|         watcher3.setFuture (QtConcurrent::run (std::bind (fast_decode_,&d2b[0], | ||||
|                                                           &narg[0],&m_TRperiod,&m_msg[0][0], | ||||
|                                                           dec_data.params.mycall,dec_data.params.hiscall,8000,12,12))); | ||||
|       } else { | ||||
|         mem_jt9->lock (); | ||||
|         memcpy(to, from, qMin(mem_jt9->size(), size)); | ||||
|         mem_jt9->unlock (); | ||||
|         to_jt9(m_ihsym,1,-1);                //Send m_ihsym to jt9[.exe] and start decoding
 | ||||
|         decodeBusy(true); | ||||
|       } | ||||
|     } | ||||
|     static short int d2b[360000]; | ||||
|     narg[0]=dec_data.params.nutc; | ||||
|     if(m_kdone>int(12000.0*m_TRperiod)) { | ||||
|       m_kdone=int(12000.0*m_TRperiod); | ||||
|     } | ||||
|     narg[1]=m_kdone; | ||||
|     narg[2]=m_nSubMode; | ||||
|     narg[3]=dec_data.params.newdat; | ||||
|     narg[4]=dec_data.params.minSync; | ||||
|     narg[5]=m_nPick; | ||||
|     narg[6]=1000.0*t0; | ||||
|     narg[7]=1000.0*t1; | ||||
|     narg[8]=2;                                //Max decode lines per decode attempt
 | ||||
|     if(dec_data.params.minSync<0) narg[8]=50; | ||||
|     if(m_mode=="ISCAT") narg[9]=101;          //ISCAT
 | ||||
|     if(m_mode=="JT9") narg[9]=102;            //Fast JT9
 | ||||
|     if(m_mode=="MSK144") narg[9]=104;         //MSK144
 | ||||
|     narg[10]=ui->RxFreqSpinBox->value(); | ||||
|     narg[11]=ui->sbFtol->value (); | ||||
|     narg[12]=0; | ||||
|     narg[13]=-1; | ||||
|     narg[14]=m_config.aggressive(); | ||||
|     memcpy(d2b,dec_data.d2,2*360000); | ||||
|     watcher3.setFuture (QtConcurrent::run (std::bind (fast_decode_,&d2b[0], | ||||
|         &narg[0],&m_TRperiod,&m_msg[0][0], | ||||
|         dec_data.params.mycall,dec_data.params.hiscall,8000,12,12))); | ||||
|   } else { | ||||
|     mem_jt9->lock (); | ||||
|     memcpy(to, from, qMin(mem_jt9->size(), size)); | ||||
|     mem_jt9->unlock (); | ||||
|     to_jt9(m_ihsym,1,-1);                //Send m_ihsym to jt9[.exe] and start decoding
 | ||||
|     decodeBusy(true); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void::MainWindow::fast_decode_done() | ||||
| @ -3219,12 +3243,14 @@ void::MainWindow::fast_decode_done() | ||||
| 
 | ||||
| void MainWindow::to_jt9(qint32 n, qint32 istart, qint32 idone) | ||||
| { | ||||
|   dec_data_t * dd = reinterpret_cast<dec_data_t *> (mem_jt9->data()); | ||||
|   mem_jt9->lock (); | ||||
|   dd->ipc[0]=n; | ||||
|   if(istart>=0) dd->ipc[1]=istart; | ||||
|   if(idone>=0)  dd->ipc[2]=idone; | ||||
|   mem_jt9->unlock (); | ||||
|   if (auto * dd = reinterpret_cast<dec_data_t *> (mem_jt9->data())) | ||||
|     { | ||||
|       mem_jt9->lock (); | ||||
|       dd->ipc[0]=n; | ||||
|       if(istart>=0) dd->ipc[1]=istart; | ||||
|       if(idone>=0)  dd->ipc[2]=idone; | ||||
|       mem_jt9->unlock (); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void MainWindow::decodeDone () | ||||
| @ -3281,7 +3307,8 @@ void MainWindow::readFromStdout()                             //readFromStdout | ||||
|             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
 | ||||
|       line_read = line_read.left(44) + "              " + line_read.mid(44); | ||||
|     } | ||||
| @ -3499,9 +3526,8 @@ void MainWindow::readFromStdout()                             //readFromStdout | ||||
|         bool okToPost=(nsec > int(4*m_TRperiod)/5); | ||||
|         if(m_mode=="FST4W" and okToPost) { | ||||
|           line_read=line_read.left(22) + " CQ " + line_read.trimmed().mid(22); | ||||
|           int n=line_read.trimmed().size(); | ||||
|           line_read=line_read.trimmed().left(n-3); | ||||
|           DecodedText FST4W_post {QString::fromUtf8(line_read.constData())}; | ||||
|           auto p = line_read.lastIndexOf (' '); | ||||
|           DecodedText FST4W_post {QString::fromUtf8 (line_read.left (p).constData ())}; | ||||
|           pskPost(FST4W_post); | ||||
|         } else { | ||||
|           if (stdMsg && okToPost) pskPost(decodedtext); | ||||
| @ -3741,26 +3767,22 @@ void MainWindow::guiUpdate() | ||||
|   if(m_mode=="WSPR" or m_mode=="FST4W") { | ||||
|     if(m_nseq==0 and m_ntr==0) {                   //Decide whether to Tx or Rx
 | ||||
|       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
 | ||||
|                                                    // scheduled transmit
 | ||||
|       if(m_auto and m_txNext) btx=true;            //TxNext button overrides
 | ||||
|       if(m_auto && ui->sbTxPercent->isEnabled () && m_pctx==100) btx=true; //Always transmit
 | ||||
| 
 | ||||
|       m_WSPR_tx_next = false; | ||||
|       if(btx) { | ||||
|         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
 | ||||
|       } else { | ||||
| // This will be a WSPR or FST4W Rx sequence.
 | ||||
|         // This will be a WSPR or FST4W Rx sequence.
 | ||||
|         m_ntr=1;                                   //This says we will have received
 | ||||
|         m_bTxTime=false;                           //Start a WSPR or FST4W Rx sequence
 | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|   } else { | ||||
| // For all modes other than WSPR and Fst4W
 | ||||
|     // For all modes other than WSPR and Fst4W
 | ||||
|     m_bTxTime = (t2p >= tx1) and (t2p < tx2); | ||||
|     if(m_mode=="Echo") m_bTxTime = m_bTxTime and m_bEchoTxOK; | ||||
|     if(m_mode=="FT8" and ui->tx5->currentText().contains("/B ")) { | ||||
| @ -4301,11 +4323,11 @@ void MainWindow::guiUpdate() | ||||
|       m_nsendingsh=0; | ||||
|       if(s[4]==64) m_nsendingsh=1; | ||||
|       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) { | ||||
|         tx_status_label.setStyleSheet("QLabel{background-color: #ffccff}"); | ||||
|         tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #ffccff}"); | ||||
|       } else { | ||||
|         tx_status_label.setStyleSheet("QLabel{background-color: #ffff33}"); | ||||
|         tx_status_label.setStyleSheet("QLabel{color: #000000; background-color: #ffff33}"); | ||||
|       } | ||||
|       if(m_tune) { | ||||
|         tx_status_label.setText("Tx: TUNE"); | ||||
| @ -4324,11 +4346,11 @@ void MainWindow::guiUpdate() | ||||
|       } | ||||
|     } else if(m_monitoring) { | ||||
|       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"); | ||||
|         if(m_mode=="MSK144") { | ||||
|           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); | ||||
|         } | ||||
|         tx_status_label.setText (t); | ||||
| @ -4649,9 +4671,9 @@ void MainWindow::doubleClickOnCall2(Qt::KeyboardModifiers modifiers) | ||||
| void MainWindow::doubleClickOnCall(Qt::KeyboardModifiers modifiers) | ||||
| { | ||||
|   QTextCursor cursor; | ||||
|   if(m_mode=="ISCAT") { | ||||
|   if(m_mode=="ISCAT" or m_mode=="FST4W") { | ||||
|     MessageBox::information_message (this, | ||||
|         "Double-click not available for ISCAT mode"); | ||||
|         "Double-click not available for ISCAT or FST4W mode"); | ||||
|     return; | ||||
|   } | ||||
|   if(m_decodedText2) { | ||||
| @ -5042,7 +5064,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie | ||||
| //        m_nextGrid=message_words.at(3);
 | ||||
| //        m_nextRpt=message.report();
 | ||||
| //        ui->labNextCall->setText("Next:  " + m_nextCall);
 | ||||
| //        ui->labNextCall->setStyleSheet("QLabel {background-color: #66ff66}");
 | ||||
| //        ui->labNextCall->setStyleSheet("QLabel {color: #000000; background-color: #66ff66}");
 | ||||
| //      }
 | ||||
|       return; | ||||
|     } | ||||
| @ -5263,11 +5285,11 @@ bool MainWindow::stdCall(QString const& w) | ||||
| { | ||||
|   static QRegularExpression standard_call_re { | ||||
|     R"( | ||||
|         ^\s*				# optional leading spaces | ||||
|         ^\s*                                      # optional leading spaces | ||||
|         ( [A-Z]{0,2} | [A-Z][0-9] | [0-9][A-Z] )  # part 1 | ||||
|         ( [0-9][A-Z]{0,3} )                       # part 2 | ||||
|         (/R | /P)?			# optional suffix | ||||
|         \s*$				# optional trailing spaces | ||||
|         (/R | /P)?                                # optional suffix | ||||
|         \s*$                                      # optional trailing spaces | ||||
|     )", QRegularExpression::CaseInsensitiveOption | QRegularExpression::ExtendedPatternSyntaxOption}; | ||||
|   return standard_call_re.match (w).hasMatch (); | ||||
| } | ||||
| @ -5384,7 +5406,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     if((m_mode!="MSK144" and m_mode!="FT8" and m_mode!="FT4")) { | ||||
|     if((m_mode!="MSK144" and m_mode!="FT8" and m_mode!="FT4" && m_mode != "FST4")) { | ||||
|       t=t00 + rpt; | ||||
|       msgtype(t, ui->tx2); | ||||
|       t=t0 + "R" + rpt; | ||||
| @ -5437,7 +5459,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) | ||||
|         case Configuration::type_2_msg_1_full: | ||||
|           msgtype(t + my_grid, ui->tx1); | ||||
|           if (!eme_short_codes) { | ||||
|             if((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4") && | ||||
|             if((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4" || m_mode == "FST4") && | ||||
|                SpecOp::NA_VHF == m_config.special_op_id()) { | ||||
|               msgtype(t + "R " + my_grid, ui->tx3); // #### Unreachable code
 | ||||
|             } else { | ||||
| @ -5450,7 +5472,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) | ||||
|           break; | ||||
| 
 | ||||
|         case Configuration::type_2_msg_3_full: | ||||
|           if ((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4") && | ||||
|           if ((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4" || m_mode == "FST4") && | ||||
|               SpecOp::NA_VHF == m_config.special_op_id()) { | ||||
|             msgtype(t + "R " + my_grid, ui->tx3); | ||||
|             msgtype(t + "RRR", ui->tx4); | ||||
| @ -5466,7 +5488,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) | ||||
|         case Configuration::type_2_msg_5_only: | ||||
|           msgtype(t00 + my_grid, ui->tx1); | ||||
|           if (!eme_short_codes) { | ||||
|             if ((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4") && | ||||
|             if ((m_mode=="MSK144" || m_mode=="FT8" || m_mode=="FT4" || m_mode == "FST4") && | ||||
|                 SpecOp::NA_VHF == m_config.special_op_id()) { | ||||
|               msgtype(t + "R " + my_grid, ui->tx3); // #### Unreachable code
 | ||||
|               msgtype(t + "RRR", ui->tx4); | ||||
| @ -5766,9 +5788,7 @@ void MainWindow::on_tx6_editingFinished()                       //tx6 edited | ||||
| 
 | ||||
| void MainWindow::on_RoundRobin_currentTextChanged(QString text) | ||||
| { | ||||
|   ui->sbTxPercent->setEnabled(text=="Random"); | ||||
|   m_WSPR_tx_next = false;       // cancel any pending Tx to avoid
 | ||||
|                                 // undesirable consecutive Tx periods
 | ||||
|   ui->sbTxPercent->setEnabled (text == tr ("Random")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| @ -6165,7 +6185,7 @@ void MainWindow::on_actionFT8_triggered() | ||||
|     ui->cbAutoSeq->setEnabled(false); | ||||
|     ui->tabWidget->setCurrentIndex(0); | ||||
|     ui->cbHoldTxFreq->setChecked(true); | ||||
|     displayWidgets(nWidgets("11101000010011000001000000000011000")); | ||||
|     displayWidgets(nWidgets("1110100001001100000100000000001100")); | ||||
|     ui->labDXped->setText(tr ("Hound")); | ||||
|     ui->txrb1->setChecked(true); | ||||
|     ui->txrb2->setEnabled(false); | ||||
| @ -6687,7 +6707,7 @@ void MainWindow::WSPR_config(bool b) | ||||
|   ui->label_7->setVisible(!b and ui->cbMenus->isChecked()); | ||||
|   ui->logQSOButton->setVisible(!b); | ||||
|   ui->DecodeButton->setEnabled(!b); | ||||
|   ui->sbTxPercent->setEnabled (m_mode != "FST4W" || "Random" == ui->RoundRobin->currentText ()); | ||||
|   ui->sbTxPercent->setEnabled (m_mode != "FST4W" || tr ("Random") == ui->RoundRobin->currentText ()); | ||||
|   ui->band_hopping_group_box->setVisible(true); | ||||
|   ui->RoundRobin->setVisible(m_mode=="FST4W"); | ||||
|   ui->RoundRobin->lineEdit()->setAlignment(Qt::AlignCenter); | ||||
| @ -6897,7 +6917,11 @@ void MainWindow::band_changed (Frequency f) | ||||
|     } | ||||
|     m_lastBand.clear (); | ||||
|     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 ("FreqCal" == m_mode) | ||||
|       { | ||||
| @ -7223,14 +7247,15 @@ void MainWindow::handle_transceiver_update (Transceiver::TransceiverState const& | ||||
| { | ||||
|   Transceiver::TransceiverState old_state {m_rigState}; | ||||
|   //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)
 | ||||
|     if (m_tx_when_ready && g_iptt) {    // waiting to Tx and still needed
 | ||||
|       int ms_delay=1000*m_config.txDelay(); | ||||
|       if(m_mode=="FT4") ms_delay=20; | ||||
|       ptt1Timer.start(ms_delay); //Start-of-transmission sequencer delay
 | ||||
|       m_tx_when_ready = false; | ||||
|     } | ||||
|     m_tx_when_ready = false; | ||||
|   } | ||||
|   m_rigState = s; | ||||
|   auto old_freqNominal = m_freqNominal; | ||||
| @ -7266,9 +7291,7 @@ void MainWindow::handle_transceiver_update (Transceiver::TransceiverState const& | ||||
|                || !(ui->cbCQTx->isEnabled () && ui->cbCQTx->isVisible () && ui->cbCQTx->isChecked()))) { | ||||
|             m_lastDialFreq = m_freqNominal; | ||||
|             m_secBandChanged=QDateTime::currentMSecsSinceEpoch()/1000; | ||||
|             if (m_config.spot_to_psk_reporter ()) { | ||||
|               pskSetLocal (); | ||||
|             } | ||||
|             pskSetLocal (); | ||||
|             statusChanged(); | ||||
|             m_wideGraph->setDialFreq(m_freqNominal / 1.e6); | ||||
|           } | ||||
| @ -7585,6 +7608,8 @@ bool MainWindow::shortList(QString callsign) | ||||
| 
 | ||||
| void MainWindow::pskSetLocal () | ||||
| { | ||||
|   if (!m_config.spot_to_psk_reporter ()) return; | ||||
| 
 | ||||
|   // find the station row, if any, that matches the band we are on
 | ||||
|   auto stations = m_config.stations (); | ||||
|   auto matches = stations->match (stations->index (0, StationList::band_column) | ||||
| @ -8070,8 +8095,8 @@ void MainWindow::p1ReadFromStdout()                        //p1readFromStdout | ||||
| 
 | ||||
| QString MainWindow::beacon_start_time (int n) | ||||
| { | ||||
|   auto bt = qt_truncate_date_time_to (QDateTime::currentDateTimeUtc ().addSecs (n), m_TRperiod); | ||||
|   if (m_TRperiod < 60) | ||||
|   auto bt = qt_truncate_date_time_to (QDateTime::currentDateTimeUtc ().addSecs (n), m_TRperiod * 1.e3); | ||||
|   if (m_TRperiod < 60.) | ||||
|     { | ||||
|       return bt.toString ("HHmmss"); | ||||
|     } | ||||
| @ -8125,17 +8150,18 @@ void MainWindow::uploadWSPRSpots (bool direct_post, QString const& decode_text) | ||||
|   QString rfreq = QString("%1").arg((m_dialFreqRxWSPR + 1500) / 1e6, 0, 'f', 6); | ||||
|   QString tfreq = QString("%1").arg((m_dialFreqRxWSPR + | ||||
|                         ui->TxFreqSpinBox->value()) / 1e6, 0, 'f', 6); | ||||
|   auto pct = QString::number (ui->autoButton->isChecked () ? ui->sbTxPercent->value () : 0); | ||||
|   if (!direct_post) | ||||
|     { | ||||
|       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 (), | ||||
|                        m_config.writeable_data_dir ().absoluteFilePath ("wspr_spots.txt")); | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       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); | ||||
|     } | ||||
|   if (!decode_text.size ()) | ||||
| @ -8161,24 +8187,9 @@ void MainWindow::on_TxPowerComboBox_currentIndexChanged(int index) | ||||
|   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) | ||||
| { | ||||
|   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) | ||||
| @ -8188,13 +8199,22 @@ void MainWindow::on_WSPRfreqSpinBox_valueChanged(int n) | ||||
| 
 | ||||
| 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 () | ||||
| { | ||||
|   if (ui->pbTxNext->isEnabled () && ui->pbTxNext->isChecked ()) | ||||
|     { | ||||
|       // Tx Next button overrides all scheduling
 | ||||
|       m_WSPR_tx_next = true; | ||||
|       return; | ||||
|     } | ||||
|   QString t=ui->RoundRobin->currentText(); | ||||
|   if(m_mode=="FST4W" and t!="Random") { | ||||
|   if(m_mode=="FST4W" and t != tr ("Random")) { | ||||
|     bool ok; | ||||
|     int i=t.left (1).toInt (&ok) - 1; | ||||
|     if (!ok) return; | ||||
| @ -8205,10 +8225,14 @@ void MainWindow::WSPR_scheduling () | ||||
|     int nsec=ms/1000; | ||||
|     int ntr=m_TRperiod; | ||||
|     int j=((nsec+ntr-1) % (n*ntr))/ntr; | ||||
|     m_WSPR_tx_next=(i==j); | ||||
|     m_WSPR_tx_next = i == j; | ||||
|     return; | ||||
|   } | ||||
|   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
 | ||||
|       && !m_config.is_dummy_rig () | ||||
|       && ui->band_hopping_group_box->isChecked ()) { | ||||
| @ -8495,7 +8519,7 @@ void MainWindow::tx_watchdog (bool triggered) | ||||
|       m_bTxTime=false; | ||||
|       if (m_tune) stop_tuning (); | ||||
|       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")); | ||||
|       QApplication::alert (this); | ||||
|     } | ||||
|  | ||||
| @ -348,6 +348,7 @@ private: | ||||
|                              int TRperiod=60) const; | ||||
|   Q_SIGNAL void outAttenuationChanged (qreal) const; | ||||
|   Q_SIGNAL void toggleShorthand () const; | ||||
|   Q_SIGNAL void reset_audio_input_stream (bool report_dropped_frames) const; | ||||
| 
 | ||||
| private: | ||||
|   void set_mode (QString const& mode); | ||||
| @ -447,7 +448,6 @@ private: | ||||
|   qint32  m_nclearave; | ||||
|   qint32  m_minSync; | ||||
|   qint32  m_dBm; | ||||
|   qint32  m_pctx; | ||||
|   qint32  m_nseq; | ||||
|   qint32  m_nWSPRdecodes; | ||||
|   qint32  m_k0; | ||||
| @ -506,7 +506,6 @@ private: | ||||
|   bool    m_bSWL; | ||||
|   bool    m_uploadWSPRSpots; | ||||
|   bool    m_uploading; | ||||
|   bool    m_txNext; | ||||
|   bool    m_grid6; | ||||
|   bool    m_tuneup; | ||||
|   bool    m_bTxTime; | ||||
| @ -668,8 +667,6 @@ private: | ||||
| 
 | ||||
|   QSharedMemory *mem_jt9; | ||||
|   QString m_QSOText; | ||||
|   unsigned m_msAudioOutputBuffered; | ||||
|   unsigned m_framesAudioInputBuffered; | ||||
|   unsigned m_downSampleFactor; | ||||
|   QThread::Priority m_audioThreadPriority; | ||||
|   bool m_bandEdited; | ||||
|  | ||||
| @ -376,6 +376,7 @@ | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QPushButton:checked { | ||||
|     color: #000000; | ||||
| 	background-color: #00ff00; | ||||
|     border-style: outset; | ||||
| 	border-width: 1px; | ||||
| @ -447,6 +448,7 @@ | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QPushButton:checked { | ||||
| 	color: rgb(0, 0, 0); | ||||
| 	background-color: cyan; | ||||
| 	border-style: outset; | ||||
| 	border-width: 1px; | ||||
| @ -480,6 +482,7 @@ | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QPushButton:checked { | ||||
| 	color: rgb(0, 0, 0); | ||||
| 	background-color: red; | ||||
| 	border-style: outset; | ||||
| 	border-width: 1px; | ||||
| @ -523,6 +526,7 @@ | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QPushButton:checked { | ||||
| 	color: rgb(0, 0, 0); | ||||
| 	background-color: red; | ||||
| 	border-style: outset; | ||||
| 	border-width: 1px; | ||||
| @ -553,43 +557,68 @@ | ||||
|      </layout> | ||||
|     </item> | ||||
|     <item> | ||||
|      <layout class="QGridLayout" name="gridLayout_5" columnstretch="0,0,0,0,0"> | ||||
|       <item row="3" column="2"> | ||||
|        <widget class="QLabel" name="labUTC"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|      <layout class="QGridLayout" name="gridLayout_5" rowstretch="1,0,1,1"> | ||||
|       <item row="0" column="1" alignment="Qt::AlignHCenter|Qt::AlignVCenter"> | ||||
|        <widget class="QPushButton" name="readFreq"> | ||||
|         <property name="enabled"> | ||||
|          <bool>false</bool> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>If orange or red there has been a rig control failure, click to reset and read the dial frequency.  S implies split mode.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="accessibleDescription"> | ||||
|          <string>If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode.</string> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QLabel { | ||||
|   font-family: MS Shell Dlg 2; | ||||
|   font-size: 16pt; | ||||
|   background-color : black; | ||||
|   color : yellow; | ||||
|          <string notr="true">QPushButton { | ||||
|  font-family: helvetica; | ||||
|  font-size: 9pt; | ||||
|  font-weight: bold; | ||||
|  background-color: white; | ||||
|  color: black; | ||||
|  border-style: solid; | ||||
|  border-width:1px; | ||||
|  border-radius:10px; | ||||
|  border-color: gray; | ||||
|  max-width:20px; | ||||
|  max-height:20px; | ||||
|  min-width:20px; | ||||
|  min-height:20px; | ||||
| } | ||||
| QPushButton[state="error"] { | ||||
|  background-color: red; | ||||
| } | ||||
| QPushButton[state="warning"] { | ||||
|  background-color: orange; | ||||
| } | ||||
| QPushButton[state="ok"] { | ||||
|  background-color: #00ff00; | ||||
| }</string> | ||||
|         </property> | ||||
|         <property name="frameShape"> | ||||
|          <enum>QFrame::StyledPanel</enum> | ||||
|         </property> | ||||
|         <property name="frameShadow"> | ||||
|          <enum>QFrame::Sunken</enum> | ||||
|         </property> | ||||
|         <property name="lineWidth"> | ||||
|          <number>2</number> | ||||
|         </property> | ||||
|         <property name="midLineWidth"> | ||||
|          <number>0</number> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string><html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html></string> | ||||
|          <string>?</string> | ||||
|         </property> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignCenter</set> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QComboBox" name="bandComboBox"> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="margin"> | ||||
|          <number>5</number> | ||||
|         <property name="accessibleName"> | ||||
|          <string>Frequency entry</string> | ||||
|         </property> | ||||
|         <property name="accessibleDescription"> | ||||
|          <string>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</string> | ||||
|         </property> | ||||
|         <property name="editable"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="insertPolicy"> | ||||
|          <enum>QComboBox::NoInsert</enum> | ||||
|         </property> | ||||
|         <property name="sizeAdjustPolicy"> | ||||
|          <enum>QComboBox::AdjustToMinimumContentsLength</enum> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
| @ -972,6 +1001,7 @@ Not available to nonstandard callsign holders.</string> | ||||
|                   <widget class="QPushButton" name="pbBestSP"> | ||||
|                    <property name="styleSheet"> | ||||
|                     <string notr="true">QPushButton:checked { | ||||
| 	color: rgb(0, 0, 0); | ||||
| 	background-color: red; | ||||
| 	border-style: outset; | ||||
| 	border-width: 1px; | ||||
| @ -1103,19 +1133,6 @@ When not checked you can view the calibration results.</string> | ||||
|                  </property> | ||||
|                 </widget> | ||||
|                </item> | ||||
|                <item row="9" column="0"> | ||||
|                 <spacer name="verticalSpacer_4"> | ||||
|                  <property name="orientation"> | ||||
|                   <enum>Qt::Vertical</enum> | ||||
|                  </property> | ||||
|                  <property name="sizeHint" stdset="0"> | ||||
|                   <size> | ||||
|                    <width>20</width> | ||||
|                    <height>40</height> | ||||
|                   </size> | ||||
|                  </property> | ||||
|                 </spacer> | ||||
|                </item> | ||||
|                <item row="3" column="1"> | ||||
|                 <widget class="QSpinBox" name="sbSerialNumber"> | ||||
|                  <property name="alignment"> | ||||
| @ -1148,6 +1165,19 @@ When not checked you can view the calibration results.</string> | ||||
|                  </property> | ||||
|                 </widget> | ||||
|                </item> | ||||
|                <item row="9" column="0"> | ||||
|                 <spacer name="verticalSpacer_4"> | ||||
|                  <property name="orientation"> | ||||
|                   <enum>Qt::Vertical</enum> | ||||
|                  </property> | ||||
|                  <property name="sizeHint" stdset="0"> | ||||
|                   <size> | ||||
|                    <width>20</width> | ||||
|                    <height>40</height> | ||||
|                   </size> | ||||
|                  </property> | ||||
|                 </spacer> | ||||
|                </item> | ||||
|               </layout> | ||||
|              </item> | ||||
|              <item> | ||||
| @ -2131,7 +2161,13 @@ list. The list can be maintained in Settings (F2).</string> | ||||
|                     <item> | ||||
|                      <widget class="QSpinBox" name="sbTxPercent"> | ||||
|                       <property name="toolTip"> | ||||
|                        <string>Percentage of 2-minute sequences devoted to transmitting.</string> | ||||
|                        <string>Percentage of minute sequences devoted to transmitting.</string> | ||||
|                       </property> | ||||
|                       <property name="styleSheet"> | ||||
|                        <string notr="true">QSpinBox:enabled[notx="true"] { | ||||
| 	color: rgb(0, 0, 0); | ||||
| 	background-color: rgb(255, 255, 0); | ||||
| }</string> | ||||
|                       </property> | ||||
|                       <property name="alignment"> | ||||
|                        <set>Qt::AlignCenter</set> | ||||
| @ -2316,6 +2352,12 @@ list. The list can be maintained in Settings (F2).</string> | ||||
|                           <property name="toolTip"> | ||||
|                            <string>Upload decoded messages to WSPRnet.org.</string> | ||||
|                           </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"> | ||||
|                            <string>Upload spots</string> | ||||
|                           </property> | ||||
| @ -2351,10 +2393,11 @@ list. The list can be maintained in Settings (F2).</string> | ||||
|                         <item> | ||||
|                          <widget class="QPushButton" name="pbTxNext"> | ||||
|                           <property name="toolTip"> | ||||
|                            <string>Transmit during the next 2-minute sequence.</string> | ||||
|                            <string><html><head/><body><p>Transmit during the next sequence.</p></body></html></string> | ||||
|                           </property> | ||||
|                           <property name="styleSheet"> | ||||
|                            <string notr="true">QPushButton:checked { | ||||
| 	color: rgb(0, 0, 0); | ||||
| 	background-color: red; | ||||
| 	border-style: outset; | ||||
| 	border-width: 1px; | ||||
| @ -2440,6 +2483,39 @@ list. The list can be maintained in Settings (F2).</string> | ||||
|         </widget> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="2"> | ||||
|        <widget class="QLabel" name="labDialFreq"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string>USB dial frequency</string> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QLabel { | ||||
|   font-family: MS Shell Dlg 2; | ||||
|   font-size: 16pt; | ||||
|    color : yellow; | ||||
|    background-color : black; | ||||
| } | ||||
| QLabel[oob="true"] { | ||||
|   background-color: red; | ||||
| }</string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>14.078 000</string> | ||||
|         </property> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignCenter</set> | ||||
|         </property> | ||||
|         <property name="margin"> | ||||
|          <number>5</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="4"> | ||||
|        <widget class="QLabel" name="label"> | ||||
|         <property name="text"> | ||||
| @ -2447,6 +2523,123 @@ list. The list can be maintained in Settings (F2).</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="3" column="2"> | ||||
|        <widget class="QLabel" name="labUTC"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QLabel { | ||||
|   font-family: MS Shell Dlg 2; | ||||
|   font-size: 16pt; | ||||
|   background-color : black; | ||||
|   color : yellow; | ||||
| }</string> | ||||
|         </property> | ||||
|         <property name="frameShape"> | ||||
|          <enum>QFrame::StyledPanel</enum> | ||||
|         </property> | ||||
|         <property name="frameShadow"> | ||||
|          <enum>QFrame::Sunken</enum> | ||||
|         </property> | ||||
|         <property name="lineWidth"> | ||||
|          <number>2</number> | ||||
|         </property> | ||||
|         <property name="midLineWidth"> | ||||
|          <number>0</number> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string><html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html></string> | ||||
|         </property> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignCenter</set> | ||||
|         </property> | ||||
|         <property name="margin"> | ||||
|          <number>5</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="0" rowspan="2"> | ||||
|        <widget class="SignalMeter" name="signal_meter_widget"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="maximumSize"> | ||||
|          <size> | ||||
|           <width>100</width> | ||||
|           <height>16777215</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>30dB recommended when only noise present<br/>Green when good<br/>Red when clipping may occur<br/>Yellow when too low</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="accessibleName"> | ||||
|          <string>Rx Signal</string> | ||||
|         </property> | ||||
|         <property name="accessibleDescription"> | ||||
|          <string>30dB recommended when only noise present | ||||
| Green when good | ||||
| Red when clipping may occur | ||||
| Yellow when too low</string> | ||||
|         </property> | ||||
|         <property name="frameShape"> | ||||
|          <enum>QFrame::Panel</enum> | ||||
|         </property> | ||||
|         <property name="frameShadow"> | ||||
|          <enum>QFrame::Sunken</enum> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="4" rowspan="3"> | ||||
|        <widget class="QSlider" name="outAttenuation"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Adjust Tx audio level</string> | ||||
|         </property> | ||||
|         <property name="maximum"> | ||||
|          <number>450</number> | ||||
|         </property> | ||||
|         <property name="value"> | ||||
|          <number>0</number> | ||||
|         </property> | ||||
|         <property name="orientation"> | ||||
|          <enum>Qt::Vertical</enum> | ||||
|         </property> | ||||
|         <property name="invertedAppearance"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="invertedControls"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="tickPosition"> | ||||
|          <enum>QSlider::TicksBelow</enum> | ||||
|         </property> | ||||
|         <property name="tickInterval"> | ||||
|          <number>50</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QSpinBox" name="sbNB"> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignCenter</set> | ||||
|         </property> | ||||
|         <property name="suffix"> | ||||
|          <string>  %</string> | ||||
|         </property> | ||||
|         <property name="prefix"> | ||||
|          <string>NB  </string> | ||||
|         </property> | ||||
|         <property name="maximum"> | ||||
|          <number>25</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="2"> | ||||
|        <widget class="QWidget" name="DX_controls_widget" native="true"> | ||||
|         <property name="sizePolicy"> | ||||
| @ -2723,182 +2916,6 @@ list. The list can be maintained in Settings (F2).</string> | ||||
|         </layout> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="0"> | ||||
|        <widget class="QComboBox" name="bandComboBox"> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="accessibleName"> | ||||
|          <string>Frequency entry</string> | ||||
|         </property> | ||||
|         <property name="accessibleDescription"> | ||||
|          <string>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</string> | ||||
|         </property> | ||||
|         <property name="editable"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="insertPolicy"> | ||||
|          <enum>QComboBox::NoInsert</enum> | ||||
|         </property> | ||||
|         <property name="sizeAdjustPolicy"> | ||||
|          <enum>QComboBox::AdjustToMinimumContentsLength</enum> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="1" alignment="Qt::AlignHCenter|Qt::AlignVCenter"> | ||||
|        <widget class="QPushButton" name="readFreq"> | ||||
|         <property name="enabled"> | ||||
|          <bool>false</bool> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>If orange or red there has been a rig control failure, click to reset and read the dial frequency.  S implies split mode.</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="accessibleDescription"> | ||||
|          <string>If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode.</string> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QPushButton { | ||||
|  font-family: helvetica; | ||||
|  font-size: 9pt; | ||||
|  font-weight: bold; | ||||
|  background-color: white; | ||||
|  color: black; | ||||
|  border-style: solid; | ||||
|  border-width:1px; | ||||
|  border-radius:10px; | ||||
|  border-color: gray; | ||||
|  max-width:20px; | ||||
|  max-height:20px; | ||||
|  min-width:20px; | ||||
|  min-height:20px; | ||||
| } | ||||
| QPushButton[state="error"] { | ||||
|  background-color: red; | ||||
| } | ||||
| QPushButton[state="warning"] { | ||||
|  background-color: orange; | ||||
| } | ||||
| QPushButton[state="ok"] { | ||||
|  background-color: #00ff00; | ||||
| }</string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>?</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="4" rowspan="2"> | ||||
|        <widget class="QSlider" name="outAttenuation"> | ||||
|         <property name="toolTip"> | ||||
|          <string>Adjust Tx audio level</string> | ||||
|         </property> | ||||
|         <property name="maximum"> | ||||
|          <number>450</number> | ||||
|         </property> | ||||
|         <property name="value"> | ||||
|          <number>0</number> | ||||
|         </property> | ||||
|         <property name="orientation"> | ||||
|          <enum>Qt::Vertical</enum> | ||||
|         </property> | ||||
|         <property name="invertedAppearance"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="invertedControls"> | ||||
|          <bool>true</bool> | ||||
|         </property> | ||||
|         <property name="tickPosition"> | ||||
|          <enum>QSlider::TicksBelow</enum> | ||||
|         </property> | ||||
|         <property name="tickInterval"> | ||||
|          <number>50</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="2" column="0" rowspan="2"> | ||||
|        <widget class="SignalMeter" name="signal_meter_widget"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="maximumSize"> | ||||
|          <size> | ||||
|           <width>100</width> | ||||
|           <height>16777215</height> | ||||
|          </size> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string><html><head/><body><p>30dB recommended when only noise present<br/>Green when good<br/>Red when clipping may occur<br/>Yellow when too low</p></body></html></string> | ||||
|         </property> | ||||
|         <property name="accessibleName"> | ||||
|          <string>Rx Signal</string> | ||||
|         </property> | ||||
|         <property name="accessibleDescription"> | ||||
|          <string>30dB recommended when only noise present | ||||
| Green when good | ||||
| Red when clipping may occur | ||||
| Yellow when too low</string> | ||||
|         </property> | ||||
|         <property name="frameShape"> | ||||
|          <enum>QFrame::Panel</enum> | ||||
|         </property> | ||||
|         <property name="frameShadow"> | ||||
|          <enum>QFrame::Sunken</enum> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="0" column="2"> | ||||
|        <widget class="QLabel" name="labDialFreq"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="toolTip"> | ||||
|          <string>USB dial frequency</string> | ||||
|         </property> | ||||
|         <property name="styleSheet"> | ||||
|          <string notr="true">QLabel { | ||||
|   font-family: MS Shell Dlg 2; | ||||
|   font-size: 16pt; | ||||
|    color : yellow; | ||||
|    background-color : black; | ||||
| } | ||||
| QLabel[oob="true"] { | ||||
|   background-color: red; | ||||
| } | ||||
| </string> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>14.078 000</string> | ||||
|         </property> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignCenter</set> | ||||
|         </property> | ||||
|         <property name="margin"> | ||||
|          <number>5</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item row="1" column="0"> | ||||
|        <widget class="QSpinBox" name="sbNB"> | ||||
|         <property name="alignment"> | ||||
|          <set>Qt::AlignCenter</set> | ||||
|         </property> | ||||
|         <property name="suffix"> | ||||
|          <string>  %</string> | ||||
|         </property> | ||||
|         <property name="prefix"> | ||||
|          <string>NB  </string> | ||||
|         </property> | ||||
|         <property name="maximum"> | ||||
|          <number>25</number> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|    </layout> | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user