diff --git a/.gitattributes b/.gitattributes index 93434826f..b1e1bbf70 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ .gitattributes export-ignore /samples export-ignore /lib/fsk4hf export-ignore +/lib/fsk4hf export-ignore +/robots export-ignore diff --git a/Audio/tools/record_time_signal.cpp b/Audio/tools/record_time_signal.cpp new file mode 100644 index 000000000..6a78a0a2c --- /dev/null +++ b/Audio/tools/record_time_signal.cpp @@ -0,0 +1,397 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "revision_utils.hpp" +#include "Audio/BWFFile.hpp" + +namespace +{ + QTextStream qtout {stdout}; +} + +class Record final + : public QObject +{ + Q_OBJECT; + +public: + Record (int start, int duration, QAudioDeviceInfo const& source_device, BWFFile * output, int notify_interval, int buffer_size) + : source_ {source_device, output->format ()} + , notify_interval_ {notify_interval} + , output_ {output} + , duration_ {duration} + { + if (buffer_size) source_.setBufferSize (output_->format ().bytesForFrames (buffer_size)); + if (notify_interval_) + { + source_.setNotifyInterval (notify_interval); + connect (&source_, &QAudioInput::notify, this, &Record::notify); + } + + if (start == -1) + { + start_recording (); + } + else + { + auto now = QDateTime::currentDateTimeUtc (); + auto time = now.time (); + auto then = now; + then.setTime (QTime {time.hour (), time.minute (), start}); + auto delta_ms = (now.msecsTo (then) + (60 * 1000)) % (60 * 1000); + QTimer::singleShot (int (delta_ms), Qt::PreciseTimer, this, &Record::start_recording); + } + } + + Q_SIGNAL void done (); + +private: + Q_SLOT void start_recording () + { + qtout << "started recording at " << QDateTime::currentDateTimeUtc ().toString ("hh:mm:ss.zzz UTC") << endl; + source_.start (output_); + if (!notify_interval_) QTimer::singleShot (duration_ * 1000, Qt::PreciseTimer, this, &Record::stop_recording); + qtout << QString {"buffer size used is: %1"}.arg (source_.bufferSize ()) << endl; + } + + Q_SLOT void notify () + { + auto length = source_.elapsedUSecs (); + qtout << QString {"%1 μs recorded\r"}.arg (length) << flush; + if (length >= duration_ * 1000 * 1000) stop_recording (); + } + + Q_SLOT void stop_recording () + { + auto length = source_.elapsedUSecs (); + source_.stop (); + qtout << QString {"%1 μs recorded "}.arg (length) << '(' << source_.format ().framesForBytes (output_->size ()) << " frames recorded)\n"; + qtout << "stopped recording at " << QDateTime::currentDateTimeUtc ().toString ("hh:mm:ss.zzz UTC") << endl; + Q_EMIT done (); + } + + QAudioInput source_; + int notify_interval_; + BWFFile * output_; + int duration_; +}; + +class Playback final + : public QObject +{ + Q_OBJECT; + +public: + Playback (int start, BWFFile * input, QAudioDeviceInfo const& sink_device, int notify_interval, int buffer_size, QString const& category) + : input_ {input} + , sink_ {sink_device, input->format ()} + , notify_interval_ {notify_interval} + { + if (buffer_size) sink_.setBufferSize (input_->format ().bytesForFrames (buffer_size)); + if (category.size ()) sink_.setCategory (category); + if (notify_interval_) + { + sink_.setNotifyInterval (notify_interval); + connect (&sink_, &QAudioOutput::notify, this, &Playback::notify); + } + connect (&sink_, &QAudioOutput::stateChanged, this, &Playback::sink_state_changed); + if (start == -1) + { + start_playback (); + } + else + { + auto now = QDateTime::currentDateTimeUtc (); + auto time = now.time (); + auto then = now; + then.setTime (QTime {time.hour (), time.minute (), start}); + auto delta_ms = (now.msecsTo (then) + (60 * 1000)) % (60 * 1000); + QTimer::singleShot (int (delta_ms), Qt::PreciseTimer, this, &Playback::start_playback); + } + } + + Q_SIGNAL void done (); + +private: + Q_SLOT void start_playback () + { + qtout << "started playback at " << QDateTime::currentDateTimeUtc ().toString ("hh:mm:ss.zzz UTC") << endl; + sink_.start (input_); + qtout << QString {"buffer size used is: %1 (%2 frames)"}.arg (sink_.bufferSize ()).arg (sink_.format ().framesForBytes (sink_.bufferSize ())) << endl; + } + + Q_SLOT void notify () + { + auto length = sink_.elapsedUSecs (); + qtout << QString {"%1 μs rendered\r"}.arg (length) << flush; + } + + Q_SLOT void sink_state_changed (QAudio::State state) + { + switch (state) + { + case QAudio::ActiveState: + qtout << "\naudio output state changed to active\n"; + break; + case QAudio::SuspendedState: + qtout << "\naudio output state changed to suspended\n"; + break; + case QAudio::StoppedState: + qtout << "\naudio output state changed to stopped\n"; + break; + case QAudio::IdleState: + stop_playback (); + qtout << "\naudio output state changed to idle\n"; + break; +#if QT_VERSION >= QT_VERSION_CHECK (5, 10, 0) + case QAudio::InterruptedState: + qtout << "\naudio output state changed to interrupted\n"; + break; +#endif + } + } + + Q_SLOT void stop_playback () + { + auto length = sink_.elapsedUSecs (); + sink_.stop (); + qtout << QString {"%1 μs rendered "}.arg (length) << '(' << sink_.format ().framesForBytes (input_->size ()) << " frames rendered)\n"; + qtout << "stopped playback at " << QDateTime::currentDateTimeUtc ().toString ("hh:mm:ss.zzz UTC") << endl; + Q_EMIT done (); + } + + BWFFile * input_; + QAudioOutput sink_; + int notify_interval_; +}; + +#include "record_time_signal.moc" + +int main(int argc, char *argv[]) +{ + QCoreApplication app {argc, argv}; + try + { + ::setlocale (LC_NUMERIC, "C"); // ensure number forms are in + // consistent format, do this + // after instantiating + // QApplication so that Qt has + // correct l18n + + // Override programs executable basename as application name. + app.setApplicationName ("WSJT-X Record Time Signal"); + app.setApplicationVersion (version ()); + + QCommandLineParser parser; + parser.setApplicationDescription ( + "\nTool to determine and experiment with QAudioInput latencies\n\n" + "\tUse the -I option to list available recording device numbers\n" + ); + auto help_option = parser.addHelpOption (); + auto version_option = parser.addVersionOption (); + + parser.addOptions ({ + {{"I", "list-audio-inputs"}, + app.translate ("main", "List the available audio input devices")}, + {{"O", "list-audio-outputs"}, + app.translate ("main", "List the available audio output devices")}, + {{"s", "start-time"}, + app.translate ("main", "Record from seconds, default start immediately"), + app.translate ("main", "start-time")}, + {{"d", "duration"}, + app.translate ("main", "Recording seconds"), + app.translate ("main", "duration")}, + {{"o", "output"}, + app.translate ("main", "Save output as "), + app.translate ("main", "output-file")}, + {{"i", "input"}, + app.translate ("main", "Playback "), + app.translate ("main", "input-file")}, + {{"f", "force"}, + app.translate ("main", "Overwrite existing file")}, + {{"r", "sample-rate"}, + app.translate ("main", "Record at , default 48000 Hz"), + app.translate ("main", "sample-rate")}, + {{"c", "num-channels"}, + app.translate ("main", "Record channels, default 2"), + app.translate ("main", "num")}, + {{"R", "recording-device-number"}, + app.translate ("main", "Record from "), + app.translate ("main", "device-number")}, + {{"P", "playback-device-number"}, + app.translate ("main", "Playback to "), + app.translate ("main", "device-number")}, + {{"C", "category"}, + app.translate ("main", "Playback "), + app.translate ("main", "category-name")}, + {{"n", "notify-interval"}, + app.translate ("main", "use notify signals every milliseconds, zero to use a timer"), + app.translate ("main", "interval")}, + {{"b", "buffer-size"}, + app.translate ("main", "audio buffer size "), + app.translate ("main", "frames")}, + }); + parser.process (app); + + auto input_devices = QAudioDeviceInfo::availableDevices (QAudio::AudioInput); + if (parser.isSet ("I")) + { + int n {0}; + for (auto const& device : input_devices) + { + qtout << ++n << " - [" << device.deviceName () << ']' << endl; + } + return 0; + } + + auto output_devices = QAudioDeviceInfo::availableDevices (QAudio::AudioOutput); + if (parser.isSet ("O")) + { + int n {0}; + for (auto const& device : output_devices) + { + qtout << ++n << " - [" << device.deviceName () << ']' << endl; + } + return 0; + } + + bool ok; + int start {-1}; + if (parser.isSet ("s")) + { + start = parser.value ("s").toInt (&ok); + if (!ok) throw std::invalid_argument {"start time not a number"}; + if (0 > start || start > 59) throw std::invalid_argument {"0 > start > 59"}; + } + int sample_rate {48000}; + if (parser.isSet ("r")) + { + sample_rate = parser.value ("r").toInt (&ok); + if (!ok) throw std::invalid_argument {"sample rate not a number"}; + } + int num_channels {2}; + if (parser.isSet ("c")) + { + num_channels = parser.value ("c").toInt (&ok); + if (!ok) throw std::invalid_argument {"channel count not a number"}; + } + int notify_interval {0}; + if (parser.isSet ("n")) + { + notify_interval = parser.value ("n").toInt (&ok); + if (!ok) throw std::invalid_argument {"notify interval not a number"}; + } + int buffer_size {0}; + if (parser.isSet ("b")) + { + buffer_size = parser.value ("b").toInt (&ok); + if (!ok) throw std::invalid_argument {"buffer size not a number"}; + } + int input_device {0}; + if (parser.isSet ("R")) + { + input_device = parser.value ("R").toInt (&ok); + if (!ok || 0 >= input_device || input_device > input_devices.size ()) + { + throw std::invalid_argument {"invalid recording device"}; + } + } + int output_device {0}; + if (parser.isSet ("P")) + { + output_device = parser.value ("P").toInt (&ok); + if (!ok || 0 >= output_device || output_device > output_devices.size ()) + { + throw std::invalid_argument {"invalid playback device"}; + } + } + if (!(parser.isSet ("o") || parser.isSet ("i"))) throw std::invalid_argument {"file required"}; + if (parser.isSet ("o") && parser.isSet ("i")) throw std::invalid_argument {"specify either input or output"}; + + QAudioFormat audio_format; + if (parser.isSet ("o")) // Record + { + int duration = parser.value ("d").toInt (&ok); + if (!ok) throw std::invalid_argument {"duration not a number"}; + + QFileInfo ofi {parser.value ("o")}; + if (!ofi.suffix ().size () && ofi.fileName ()[ofi.fileName ().size () - 1] != QChar {'.'}) + { + ofi.setFile (ofi.filePath () + ".wav"); + } + if (!parser.isSet ("f") && ofi.isFile ()) + { + throw std::invalid_argument {"set the `-force' option to overwrite an existing output file"}; + } + + audio_format.setSampleRate (sample_rate); + audio_format.setChannelCount (num_channels); + audio_format.setSampleSize (16); + audio_format.setSampleType (QAudioFormat::SignedInt); + audio_format.setCodec ("audio/pcm"); + + auto source = input_device ? input_devices[input_device - 1] : QAudioDeviceInfo::defaultInputDevice (); + if (!source.isFormatSupported (audio_format)) + { + qtout << "warning, requested format not supported, using nearest" << endl; + audio_format = source.nearestFormat (audio_format); + } + BWFFile output_file {audio_format, ofi.filePath ()}; + if (!output_file.open (BWFFile::WriteOnly)) throw std::invalid_argument {QString {"cannot open output file \"%1\""}.arg (ofi.filePath ()).toStdString ()}; + + // run the application + Record record {start, duration, source, &output_file, notify_interval, buffer_size}; + QObject::connect (&record, &Record::done, &app, &QCoreApplication::quit); + return app.exec(); + } + else // Playback + { + QFileInfo ifi {parser.value ("i")}; + if (!ifi.isFile () && !ifi.suffix ().size () && ifi.fileName ()[ifi.fileName ().size () - 1] != QChar {'.'}) + { + ifi.setFile (ifi.filePath () + ".wav"); + } + BWFFile input_file {audio_format, ifi.filePath ()}; + if (!input_file.open (BWFFile::ReadOnly)) throw std::invalid_argument {QString {"cannot open input file \"%1\""}.arg (ifi.filePath ()).toStdString ()}; + auto sink = output_device ? output_devices[output_device - 1] : QAudioDeviceInfo::defaultOutputDevice (); + if (!sink.isFormatSupported (input_file.format ())) + { + throw std::invalid_argument {"audio output device does not support input file audio format"}; + } + + // run the application + Playback play {start, &input_file, sink, notify_interval, buffer_size, parser.value ("category")}; + QObject::connect (&play, &Playback::done, &app, &QCoreApplication::quit); + return app.exec(); + } + } + catch (std::exception const& e) + { + std::cerr << "Error: " << e.what () << '\n'; + } + catch (...) + { + std::cerr << "Unexpected fatal error\n"; + throw; // hoping the runtime might tell us more about the exception + } + return -1; +} diff --git a/CMake/Modules/Findhamlib.cmake b/CMake/Modules/Findhamlib.cmake index 98419bda1..234083ae1 100644 --- a/CMake/Modules/Findhamlib.cmake +++ b/CMake/Modules/Findhamlib.cmake @@ -19,9 +19,12 @@ find_path (__hamlib_pc_path NAMES hamlib.pc PATH_SUFFIXES lib/pkgconfig lib64/pkgconfig ) if (__hamlib_pc_path) - set (ENV{PKG_CONFIG_PATH} "${__hamlib_pc_path}" "$ENV{PKG_CONFIG_PATH}") - unset (__hamlib_pc_path CACHE) + set (__pc_path $ENV{PKG_CONFIG_PATH}) + list (APPEND __pc_path "${__hamlib_pc_path}") + set (ENV{PKG_CONFIG_PATH} "${__pc_path}") + unset (__pc_path CACHE) endif () +unset (__hamlib_pc_path CACHE) # Use pkg-config to get hints about paths, libs and, flags unset (__pkg_config_checked_hamlib CACHE) diff --git a/CMakeLists.txt b/CMakeLists.txt index db716d464..8f3cb28db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,10 @@ if (POLICY CMP0063) cmake_policy (SET CMP0063 NEW) # honour visibility properties for all library types endif (POLICY CMP0063) +if (POLICY CMP0071) + cmake_policy (SET CMP0071 NEW) # run automoc and autouic on generated sources +endif (POLICY CMP0071) + include (${PROJECT_SOURCE_DIR}/CMake/VersionCompute.cmake) message (STATUS "Building ${CMAKE_PROJECT_NAME}-${wsjtx_VERSION}") @@ -181,7 +185,11 @@ attach a debugger which will then receive the console output inside its console. set (PROJECT_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}") if (NOT PROJECT_ARCHITECTURE) # This is supposed to happen already on Windows - set (PROJECT_ARCHITECTURE "$ENV{PROCESSOR_ARCHITECTURE}") + if (CMAKE_SIZEOF_VOID_P MATCHES 8) + set (PROJECT_ARCHITECTURE "x64") + else () + set (PROJECT_ARCHITECTURE "$ENV{PROCESSOR_ARCHITECTURE}") + endif () endif (NOT PROJECT_ARCHITECTURE) message (STATUS "******************************************************") message (STATUS "Building for for: ${CMAKE_SYSTEM_NAME}-${PROJECT_ARCHITECTURE}") @@ -229,6 +237,7 @@ set (wsjt_qt_CXXSRCS models/FrequencyList.cpp models/StationList.cpp widgets/FrequencyLineEdit.cpp + widgets/FrequencyDeltaLineEdit.cpp item_delegates/CandidateKeyFilter.cpp item_delegates/ForeignKeyDelegate.cpp validators/LiveFrequencyValidator.cpp @@ -271,9 +280,12 @@ set (wsjt_qt_CXXSRCS widgets/CabrilloLogWindow.cpp item_delegates/CallsignDelegate.cpp item_delegates/MaidenheadLocatorDelegate.cpp + item_delegates/FrequencyDelegate.cpp + item_delegates/FrequencyDeltaDelegate.cpp models/CabrilloLog.cpp logbook/AD1CCty.cpp logbook/WorkedBefore.cpp + logbook/Multiplier.cpp ) set (wsjt_qtmm_CXXSRCS @@ -356,6 +368,7 @@ set (wsjt_FSRCS lib/jt65_decode.f90 lib/jt65_mod.f90 lib/ft8_decode.f90 + lib/ft4_decode.f90 lib/jt9_decode.f90 lib/options.f90 lib/packjt.f90 @@ -381,6 +394,7 @@ set (wsjt_FSRCS lib/azdist.f90 lib/badmsg.f90 lib/ft8/baseline.f90 + lib/ft4/ft4_baseline.f90 lib/bpdecode40.f90 lib/bpdecode128_90.f90 lib/ft8/bpdecode174_91.f90 @@ -394,6 +408,7 @@ set (wsjt_FSRCS lib/chkhist.f90 lib/chkmsg.f90 lib/chkss2.f90 + lib/ft4/clockit.f90 lib/ft8/compress.f90 lib/coord.f90 lib/db.f90 @@ -455,6 +470,7 @@ set (wsjt_FSRCS lib/ft8.f90 lib/ft8dec.f90 lib/ft8/ft8sim.f90 + lib/ft8/ft8sim_gfsk.f90 lib/gen4.f90 lib/gen65.f90 lib/gen9.f90 @@ -462,12 +478,16 @@ set (wsjt_FSRCS lib/ft8/genft8.f90 lib/genmsk_128_90.f90 lib/genmsk40.f90 + lib/ft4/genft4.f90 + lib/ft4/gen_ft4wave.f90 + lib/ft8/gen_ft8wave.f90 lib/genqra64.f90 lib/ft8/genft8refsig.f90 lib/genwspr.f90 lib/geodist.f90 lib/getlags.f90 lib/getmet4.f90 + lib/ft2/gfsk_pulse.f90 lib/graycode.f90 lib/graycode65.f90 lib/grayline.f90 @@ -506,6 +526,10 @@ set (wsjt_FSRCS lib/msk144signalquality.f90 lib/msk144sim.f90 lib/mskrtd.f90 + lib/nuttal_window.f90 + lib/ft4/ft4sim.f90 + lib/ft4/ft4sim_mult.f90 + lib/ft4/ft4_downsample.f90 lib/77bit/my_hash.f90 lib/wsprd/osdwspr.f90 lib/ft8/osd174_91.f90 @@ -539,6 +563,7 @@ set (wsjt_FSRCS lib/stdmsg.f90 lib/subtract65.f90 lib/ft8/subtractft8.f90 + lib/ft4/subtractft4.f90 lib/sun.f90 lib/symspec.f90 lib/symspec2.f90 @@ -546,8 +571,11 @@ set (wsjt_FSRCS lib/sync4.f90 lib/sync64.f90 lib/sync65.f90 + lib/ft4/getcandidates4.f90 + lib/ft4/get_ft4_bitmetrics.f90 lib/ft8/sync8.f90 lib/ft8/sync8d.f90 + lib/ft4/sync4d.f90 lib/sync9.f90 lib/sync9f.f90 lib/sync9w.f90 @@ -794,7 +822,7 @@ if (WIN32) endif (NOT AXSERVER) string (REPLACE "\"" "" AXSERVER ${AXSERVER}) file (TO_CMAKE_PATH ${AXSERVER} AXSERVERSRCS) -endif (WIN32) +endif () # @@ -827,9 +855,6 @@ if (Boost_NO_SYSTEM_PATHS) set (BOOST_ROOT ${PROJECT_SOURCE_DIR}/boost) endif () find_package (Boost 1.63 REQUIRED) -if (Boost_FOUND) - include_directories (${Boost_INCLUDE_DIRS}) -endif () # # OpenMP @@ -860,10 +885,7 @@ message (STATUS "hamlib_LIBRARY_DIRS: ${hamlib_LIBRARY_DIRS}") # # Widgets finds its own dependencies. -find_package (Qt5Widgets 5 REQUIRED) -find_package (Qt5Multimedia 5 REQUIRED) -find_package (Qt5PrintSupport 5 REQUIRED) -find_package (Qt5Sql 5 REQUIRED) +find_package (Qt5 COMPONENTS Widgets Multimedia PrintSupport Sql LinguistTools REQUIRED) if (WIN32) add_definitions (-DQT_NEEDS_QTMAIN) @@ -1069,11 +1091,41 @@ add_custom_target (ctags COMMAND ${CTAGS} -o ${CMAKE_SOURCE_DIR}/tags -R ${sourc add_custom_target (etags COMMAND ${ETAGS} -o ${CMAKE_SOURCE_DIR}/TAGS -R ${sources}) +# Qt i18n +set (LANGUAGES + en_GB + pt_PT + ) +foreach (lang_ ${LANGUAGES}) + file (TO_NATIVE_PATH translations/wsjtx_${lang_}.ts ts_) + list (APPEND TS_FILES ${ts_}) +endforeach () +if (UPDATE_TRANSLATIONS) + message (STATUS "UPDATE_TRANSLATIONS option is set.") + qt5_create_translation ( + QM_FILES ${wsjt_qt_UISRCS} ${wsjtx_UISRCS} ${wsjt_qt_CXXSRCS} ${wsjtx_CXXSRCS} + ${TS_FILES} + ) +else () + qt5_add_translation (QM_FILES ${TS_FILES}) +endif () +add_custom_target (translations DEPENDS ${QM_FILES}) +set_property (DIRECTORY PROPERTY CLEAN_NO_CUSTOM TRUE) +# do this after i18n to stop lupdate walking the boost tree which it +# chokes on +if (Boost_FOUND) + include_directories (${Boost_INCLUDE_DIRS}) +endif () + # embedded resources function (add_resources resources path) foreach (resource_file_ ${ARGN}) get_filename_component (name_ ${resource_file_} NAME) - file (TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${resource_file_} source_) + if (IS_ABSOLUTE "${resource_file_}") + file (TO_NATIVE_PATH ${resource_file_} source_) + else () + file (TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${resource_file_} source_) + endif () file (TO_NATIVE_PATH ${path}/${name_} dest_) set (resources_ "${resources_}\n ${source_}") set (${resources} ${${resources}}${resources_} PARENT_SCOPE) @@ -1082,6 +1134,7 @@ endfunction (add_resources resources path) add_resources (wsjtx_RESOURCES "" ${TOP_LEVEL_RESOURCES}) add_resources (wsjtx_RESOURCES /Palettes ${PALETTE_FILES}) +add_resources (wsjtx_RESOURCES /Translations ${QM_FILES}) configure_file (wsjtx.qrc.in wsjtx.qrc @ONLY) @@ -1102,7 +1155,6 @@ if (WIN32) wrap_ax_server (GENAXSRCS ${AXSERVERSRCS}) endif (WIN32) - # # targets # @@ -1221,6 +1273,9 @@ target_link_libraries (jt49sim wsjt_fort wsjt_cxx) add_executable (allsim lib/allsim.f90 wsjtx.rc) target_link_libraries (allsim wsjt_fort wsjt_cxx) +add_executable (rtty_spec lib/rtty_spec.f90 wsjtx.rc) +target_link_libraries (rtty_spec wsjt_fort wsjt_cxx) + add_executable (jt65code lib/jt65code.f90 wsjtx.rc) target_link_libraries (jt65code wsjt_fort wsjt_cxx) @@ -1254,9 +1309,21 @@ target_link_libraries (ft8 wsjt_fort wsjt_cxx) add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc) target_link_libraries (ft8sim wsjt_fort wsjt_cxx) +add_executable (ft8sim_gfsk lib/ft8/ft8sim_gfsk.f90 wsjtx.rc) +target_link_libraries (ft8sim_gfsk wsjt_fort wsjt_cxx) + add_executable (msk144sim lib/msk144sim.f90 wsjtx.rc) target_link_libraries (msk144sim wsjt_fort wsjt_cxx) +add_executable (ft4sim lib/ft4/ft4sim.f90 wsjtx.rc) +target_link_libraries (ft4sim wsjt_fort wsjt_cxx) + +add_executable (ft4sim_mult lib/ft4/ft4sim_mult.f90 wsjtx.rc) +target_link_libraries (ft4sim_mult wsjt_fort wsjt_cxx) + +add_executable (record_time_signal Audio/tools/record_time_signal.cpp) +target_link_libraries (record_time_signal wsjt_cxx wsjt_qtmm wsjt_qt) + endif(WSJT_BUILD_UTILS) # build the main application @@ -1606,6 +1673,7 @@ if (NOT is_debug_build) install ( DIRECTORY ${QT_PLUGINS_DIR}/platforms + ${QT_PLUGINS_DIR}/styles ${QT_PLUGINS_DIR}/accessible ${QT_PLUGINS_DIR}/audio ${QT_PLUGINS_DIR}/imageformats diff --git a/Configuration.cpp b/Configuration.cpp index 8fcb5cee1..ebb6380b3 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -167,8 +167,11 @@ #include "MetaDataRegistry.hpp" #include "SettingsGroup.hpp" #include "widgets/FrequencyLineEdit.hpp" +#include "widgets/FrequencyDeltaLineEdit.hpp" #include "item_delegates/CandidateKeyFilter.hpp" #include "item_delegates/ForeignKeyDelegate.hpp" +#include "item_delegates/FrequencyDelegate.hpp" +#include "item_delegates/FrequencyDeltaDelegate.hpp" #include "TransceiverFactory.hpp" #include "Transceiver.hpp" #include "models/Bands.hpp" @@ -209,6 +212,7 @@ namespace |LB|NU|YT|PEI |DC # District of Columbia |DX # anyone else + |SCC # Slovenia Contest Club contest ) )", QRegularExpression::CaseInsensitiveOption | QRegularExpression::ExtendedPatternSyntaxOption}; @@ -247,6 +251,8 @@ namespace class FrequencyDialog final : public QDialog { + Q_OBJECT + public: using Item = FrequencyList_v2::Item; @@ -293,6 +299,8 @@ private: class StationDialog final : public QDialog { + Q_OBJECT + public: explicit StationDialog (StationList const * stations, Bands * bands, QWidget * parent = nullptr) : QDialog {parent} @@ -563,6 +571,7 @@ private: DecodeHighlightingModel decode_highlighing_model_; DecodeHighlightingModel next_decode_highlighing_model_; bool highlight_by_mode_; + bool include_WAE_entities_; int LotW_days_since_upload_; TransceiverFactory::ParameterPack rig_params_; @@ -608,6 +617,7 @@ private: bool miles_; bool quick_call_; bool disable_TX_on_73_; + bool force_call_1st_; bool alternate_bindings_; int watchdog_; bool TX_messages_; @@ -630,6 +640,7 @@ private: bool udpWindowToFront_; bool udpWindowRestore_; DataMode data_mode_; + bool bLowSidelobes_; bool pwrBandTxMemory_; bool pwrBandTuneMemory_; @@ -703,6 +714,7 @@ bool Configuration::clear_DX () const {return m_->clear_DX_;} bool Configuration::miles () const {return m_->miles_;} bool Configuration::quick_call () const {return m_->quick_call_;} bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;} +bool Configuration::force_call_1st() const {return m_->force_call_1st_;} bool Configuration::alternate_bindings() const {return m_->alternate_bindings_;} int Configuration::watchdog () const {return m_->watchdog_;} bool Configuration::TX_messages () const {return m_->TX_messages_;} @@ -714,12 +726,14 @@ bool Configuration::x2ToneSpacing() const {return m_->x2ToneSpacing_;} bool Configuration::x4ToneSpacing() const {return m_->x4ToneSpacing_;} bool Configuration::split_mode () const {return m_->split_mode ();} QString Configuration::opCall() const {return m_->opCall_;} +void Configuration::opCall (QString const& call) {m_->opCall_ = call;} QString Configuration::udp_server_name () const {return m_->udp_server_name_;} auto Configuration::udp_server_port () const -> port_type {return m_->udp_server_port_;} bool Configuration::accept_udp_requests () const {return m_->accept_udp_requests_;} QString Configuration::n1mm_server_name () const {return m_->n1mm_server_name_;} auto Configuration::n1mm_server_port () const -> port_type {return m_->n1mm_server_port_;} bool Configuration::broadcast_to_n1mm () const {return m_->broadcast_to_n1mm_;} +bool Configuration::lowSidelobes() const {return m_->bLowSidelobes_;} bool Configuration::udpWindowToFront () const {return m_->udpWindowToFront_;} bool Configuration::udpWindowRestore () const {return m_->udpWindowRestore_;} Bands * Configuration::bands () {return &m_->bands_;} @@ -739,6 +753,7 @@ bool Configuration::pwrBandTuneMemory () const {return m_->pwrBandTuneMemory_;} LotWUsers const& Configuration::lotw_users () const {return m_->lotw_users_;} DecodeHighlightingModel const& Configuration::decode_highlighting () const {return m_->decode_highlighing_model_;} bool Configuration::highlight_by_mode () const {return m_->highlight_by_mode_;} +bool Configuration::include_WAE_entities () const {return m_->include_WAE_entities_;} void Configuration::set_calibration (CalibrationParams params) { @@ -944,6 +959,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network , station_insert_action_ {tr ("&Insert ..."), nullptr} , station_dialog_ {new StationDialog {&next_stations_, &bands_, this}} , highlight_by_mode_ {false} + , include_WAE_entities_ {false} , LotW_days_since_upload_ {0} , last_port_type_ {TransceiverFactory::Capabilities::none} , rig_is_dummy_ {false} @@ -1012,6 +1028,9 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network }); lotw_users_.set_local_file_path (writeable_data_dir_.absoluteFilePath ("lotw-user-activity.csv")); + // load the dictionary if it exists + lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text (), false); + // // validation ui_->callsign_line_edit->setValidator (new CallsignValidator {this}); @@ -1070,6 +1089,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network // fill_port_combo_box (ui_->PTT_port_combo_box); ui_->PTT_port_combo_box->addItem ("CAT"); + ui_->PTT_port_combo_box->setItemData (ui_->PTT_port_combo_box->count () - 1, "Delegate to proxy CAT service", Qt::ToolTipRole); // // setup hooks to keep audio channels aligned with devices @@ -1109,9 +1129,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network ui_->frequencies_table_view->setColumnHidden (FrequencyList_v2::frequency_mhz_column, true); // delegates - auto frequencies_item_delegate = new QStyledItemDelegate {this}; - frequencies_item_delegate->setItemEditorFactory (item_editor_factory ()); - ui_->frequencies_table_view->setItemDelegate (frequencies_item_delegate); + ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::frequency_column, new FrequencyDelegate {this}); ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::region_column, new ForeignKeyDelegate {®ions_, 0, this}); ui_->frequencies_table_view->setItemDelegateForColumn (FrequencyList_v2::mode_column, new ForeignKeyDelegate {&modes_, 0, this}); @@ -1150,9 +1168,7 @@ Configuration::impl::impl (Configuration * self, QNetworkAccessManager * network ui_->stations_table_view->sortByColumn (StationList::band_column, Qt::AscendingOrder); // stations delegates - auto stations_item_delegate = new QStyledItemDelegate {this}; - stations_item_delegate->setItemEditorFactory (item_editor_factory ()); - ui_->stations_table_view->setItemDelegate (stations_item_delegate); + ui_->stations_table_view->setItemDelegateForColumn (StationList::offset_column, new FrequencyDeltaDelegate {this}); ui_->stations_table_view->setItemDelegateForColumn (StationList::band_column, new ForeignKeyDelegate {&bands_, &next_stations_, 0, StationList::band_column, this}); // stations actions @@ -1235,6 +1251,7 @@ void Configuration::impl::initialize_models () ui_->miles_check_box->setChecked (miles_); ui_->quick_call_check_box->setChecked (quick_call_); ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_); + ui_->force_call_1st_check_box->setChecked (force_call_1st_); ui_->alternate_bindings_check_box->setChecked (alternate_bindings_); ui_->tx_watchdog_spin_box->setValue (watchdog_); ui_->TX_messages_check_box->setChecked (TX_messages_); @@ -1285,6 +1302,8 @@ void Configuration::impl::initialize_models () ui_->udpWindowRestore->setChecked(udpWindowRestore_); ui_->calibration_intercept_spin_box->setValue (calibration_.intercept); ui_->calibration_slope_ppm_spin_box->setValue (calibration_.slope_ppm); + ui_->rbLowSidelobes->setChecked(bLowSidelobes_); + if(!bLowSidelobes_) ui_->rbMaxSensitivity->setChecked(true); if (rig_params_.ptt_port.isEmpty ()) { @@ -1306,6 +1325,7 @@ void Configuration::impl::initialize_models () next_decode_highlighing_model_.items (decode_highlighing_model_.items ()); ui_->highlight_by_mode_check_box->setChecked (highlight_by_mode_); + ui_->include_WAE_check_box->setChecked (include_WAE_entities_); ui_->LotW_days_since_upload_spin_box->setValue (LotW_days_since_upload_); set_rig_invariants (); @@ -1454,6 +1474,7 @@ void Configuration::impl::read_settings () if (!highlight_items.size ()) highlight_items = DecodeHighlightingModel::default_items (); decode_highlighing_model_.items (highlight_items); highlight_by_mode_ = settings_->value("HighlightByMode", false).toBool (); + include_WAE_entities_ = settings_->value("IncludeWAEEntities", false).toBool (); LotW_days_since_upload_ = settings_->value ("LotWDaysSinceLastUpload", 365).toInt (); lotw_users_.set_age_constraint (LotW_days_since_upload_); @@ -1476,6 +1497,7 @@ void Configuration::impl::read_settings () rig_params_.audio_source = settings_->value ("TXAudioSource", QVariant::fromValue (TransceiverFactory::TX_audio_source_front)).value (); rig_params_.ptt_port = settings_->value ("PTTport").toString (); data_mode_ = settings_->value ("DataMode", QVariant::fromValue (data_mode_none)).value (); + bLowSidelobes_ = settings_->value("LowSidelobes",true).toBool(); prompt_to_log_ = settings_->value ("PromptToLog", false).toBool (); autoLog_ = settings_->value ("AutoLog", false).toBool (); decodes_from_top_ = settings_->value ("DecodesFromTop", false).toBool (); @@ -1486,6 +1508,7 @@ void Configuration::impl::read_settings () miles_ = settings_->value ("Miles", false).toBool (); quick_call_ = settings_->value ("QuickCall", false).toBool (); disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool (); + force_call_1st_ = settings_->value ("ForceCallFirst", false).toBool (); alternate_bindings_ = settings_->value ("AlternateBindings", false).toBool (); watchdog_ = settings_->value ("TxWatchdog", 6).toInt (); TX_messages_ = settings_->value ("Tx2QSO", true).toBool (); @@ -1565,6 +1588,7 @@ void Configuration::impl::write_settings () settings_->setValue ("stations", QVariant::fromValue (stations_.station_list ())); settings_->setValue ("DecodeHighlighting", QVariant::fromValue (decode_highlighing_model_.items ())); settings_->setValue ("HighlightByMode", highlight_by_mode_); + settings_->setValue ("IncludeWAEEntities", include_WAE_entities_); settings_->setValue ("LotWDaysSinceLastUpload", LotW_days_since_upload_); settings_->setValue ("toRTTY", log_as_RTTY_); settings_->setValue ("dBtoComments", report_in_comments_); @@ -1577,6 +1601,7 @@ void Configuration::impl::write_settings () settings_->setValue ("CATStopBits", QVariant::fromValue (rig_params_.stop_bits)); settings_->setValue ("CATHandshake", QVariant::fromValue (rig_params_.handshake)); settings_->setValue ("DataMode", QVariant::fromValue (data_mode_)); + settings_->setValue ("LowSidelobes",bLowSidelobes_); settings_->setValue ("PromptToLog", prompt_to_log_); settings_->setValue ("AutoLog", autoLog_); settings_->setValue ("DecodesFromTop", decodes_from_top_); @@ -1587,6 +1612,7 @@ void Configuration::impl::write_settings () settings_->setValue ("Miles", miles_); settings_->setValue ("QuickCall", quick_call_); settings_->setValue ("73TxDisable", disable_TX_on_73_); + settings_->setValue ("ForceCallFirst", force_call_1st_); settings_->setValue ("AlternateBindings", alternate_bindings_); settings_->setValue ("TxWatchdog", watchdog_); settings_->setValue ("Tx2QSO", TX_messages_); @@ -2031,10 +2057,12 @@ void Configuration::impl::accept () miles_ = ui_->miles_check_box->isChecked (); quick_call_ = ui_->quick_call_check_box->isChecked (); disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked (); + force_call_1st_ = ui_->force_call_1st_check_box->isChecked (); alternate_bindings_ = ui_->alternate_bindings_check_box->isChecked (); watchdog_ = ui_->tx_watchdog_spin_box->value (); TX_messages_ = ui_->TX_messages_check_box->isChecked (); data_mode_ = static_cast (ui_->TX_mode_button_group->checkedId ()); + bLowSidelobes_ = ui_->rbLowSidelobes->isChecked(); save_directory_ = ui_->save_path_display_label->text (); azel_directory_ = ui_->azel_path_display_label->text (); enable_VHF_features_ = ui_->enable_VHF_features_check_box->isChecked (); @@ -2064,7 +2092,12 @@ void Configuration::impl::accept () Q_EMIT self_->udp_server_port_changed (new_port); } - accept_udp_requests_ = ui_->accept_udp_requests_check_box->isChecked (); + if (ui_->accept_udp_requests_check_box->isChecked () != accept_udp_requests_) + { + accept_udp_requests_ = ui_->accept_udp_requests_check_box->isChecked (); + Q_EMIT self_->accept_udp_requests_changed (accept_udp_requests_); + } + n1mm_server_name_ = ui_->n1mm_server_name_line_edit->text (); n1mm_server_port_ = ui_->n1mm_server_port_spin_box->value (); broadcast_to_n1mm_ = ui_->enable_n1mm_broadcast_check_box->isChecked (); @@ -2097,6 +2130,7 @@ void Configuration::impl::accept () Q_EMIT self_->decode_highlighting_changed (decode_highlighing_model_); } highlight_by_mode_ = ui_->highlight_by_mode_check_box->isChecked (); + include_WAE_entities_ = ui_->include_WAE_check_box->isChecked (); LotW_days_since_upload_ = ui_->LotW_days_since_upload_spin_box->value (); lotw_users_.set_age_constraint (LotW_days_since_upload_); @@ -2155,7 +2189,7 @@ void Configuration::impl::on_rescan_log_push_button_clicked (bool /*clicked*/) void Configuration::impl::on_LotW_CSV_fetch_push_button_clicked (bool /*checked*/) { - lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text (), true); + lotw_users_.load (ui_->LotW_CSV_URL_line_edit->text (), true, true); ui_->LotW_CSV_fetch_push_button->setEnabled (false); } @@ -2919,9 +2953,15 @@ void Configuration::impl::fill_port_combo_box (QComboBox * cb) // remove possibly confusing Windows device path (OK because // it gets added back by Hamlib) cb->addItem (p.systemLocation ().remove (QRegularExpression {R"(^\\\\\.\\)"})); + auto tip = QString {"%1 %2 %3"}.arg (p.manufacturer ()).arg (p.serialNumber ()).arg (p.description ()).trimmed (); + if (tip.size ()) + { + cb->setItemData (cb->count () - 1, tip, Qt::ToolTipRole); + } } } - cb->addItem("USB"); + cb->addItem ("USB"); + cb->setItemData (cb->count () - 1, "Custom USB device", Qt::ToolTipRole); cb->setEditText (current_text); } diff --git a/Configuration.hpp b/Configuration.hpp index 9aa0c286b..dbf232fd5 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -127,6 +127,7 @@ public: bool miles () const; bool quick_call () const; bool disable_TX_on_73 () const; + bool force_call_1st() const; bool alternate_bindings() const; int watchdog () const; bool TX_messages () const; @@ -137,6 +138,7 @@ public: bool twoPass() const; bool bFox() const; bool bHound() const; + bool bLowSidelobes() const; bool x2ToneSpacing() const; bool x4ToneSpacing() const; bool MyDx() const; @@ -146,12 +148,14 @@ public: bool EMEonly() const; bool post_decodes () const; QString opCall() const; + void opCall (QString const&); QString udp_server_name () const; port_type udp_server_port () const; QString n1mm_server_name () const; port_type n1mm_server_port () const; bool valid_n1mm_info () const; bool broadcast_to_n1mm() const; + bool lowSidelobes() const; bool accept_udp_requests () const; bool udpWindowToFront () const; bool udpWindowRestore () const; @@ -173,6 +177,7 @@ public: LotWUsers const& lotw_users () const; DecodeHighlightingModel const& decode_highlighting () const; bool highlight_by_mode () const; + bool include_WAE_entities () const; enum class SpecialOperatingActivity {NONE, NA_VHF, EU_VHF, FIELD_DAY, RTTY, FOX, HOUND}; SpecialOperatingActivity special_op_id () const; @@ -266,6 +271,7 @@ public: // Q_SIGNAL void udp_server_changed (QString const& udp_server) const; Q_SIGNAL void udp_server_port_changed (port_type server_port) const; + Q_SIGNAL void accept_udp_requests_changed (bool checked) const; // signal updates to decode highlighting Q_SIGNAL void decode_highlighting_changed (DecodeHighlightingModel const&) const; diff --git a/Configuration.ui b/Configuration.ui index 9bc5f35aa..a9fe51d45 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -7,7 +7,7 @@ 0 0 546 - 536 + 553 @@ -301,7 +301,14 @@ Behavior - + + + + Decode after EME delay + + + + @@ -347,10 +354,27 @@ - - + + - Decode after EME delay + Enable VHF/UHF/Microwave features + + + + + + + Single decode + + + + + + + <html><head/><body><p>Some rigs are not able to process CAT commands while transmitting. This means that if you are operating in split mode you may have to uncheck this option.</p></body></html> + + + Allow Tx frequency changes while transmitting @@ -367,31 +391,35 @@ - - - - Single decode - - - - - - - Enable VHF/UHF/Microwave features - - - - - + + - <html><head/><body><p>Some rigs are not able to process CAT commands while transmitting. This means that if you are operating in split mode you may have to uncheck this option.</p></body></html> + <html><head/><body><p>Check this if you wish to automatically return to the last monitored frequency when monitor is enabled, leave it unchecked if you wish to have the current rig frequency maintained.</p></body></html> - Allow Tx frequency changes while transmitting + Monitor returns to last used frequency - + + + + Alternate F1-F6 bindings + + + + + + + Turns off automatic transmissions after sending a 73 or any other free +text message. + + + Di&sable Tx after sending 73 + + + + @@ -444,34 +472,6 @@ quiet period when decoding is done. - - - - <html><head/><body><p>Check this if you wish to automatically return to the last monitored frequency when monitor is enabled, leave it unchecked if you wish to have the current rig frequency maintained.</p></body></html> - - - Monitor returns to last used frequency - - - - - - - Alternate F1-F5 bindings - - - - - - - Turns off automatic transmissions after sending a 73 or any other free -text message. - - - Di&sable Tx after sending 73 - - - @@ -482,6 +482,13 @@ text message. + + + + Calling CQ forces Call 1st + + + @@ -1912,7 +1919,7 @@ for assessing propagation and system performance. - N1MM Logger+ Broadcasts + Secondary UDP Server (deprecated) @@ -1928,7 +1935,7 @@ for assessing propagation and system performance. - <html><head/><body><p>N1MM Server name or IP address:</p></body></html> + Server name or IP address: n1mm_server_name_line_edit @@ -1945,7 +1952,7 @@ for assessing propagation and system performance. - <html><head/><body><p>N1MM Server port number:</p></body></html> + Server port number: n1mm_server_port_spin_box @@ -2287,6 +2294,23 @@ Right click for insert and delete options. + + + + + + + + + Include extra WAE entities + + + include_WAE_check_box + + + + + @@ -2299,35 +2323,6 @@ Right click for insert and delete options. Logbook of the World User Validation - - - - Age of last upload less than: - - - LotW_days_since_upload_spin_box - - - - - - - <html><head/><body><p>Adjust this spin box to set the age threshold of LotW user's last upload date that is accepted as a current LotW user.</p></body></html> - - - days - - - 0 - - - 9999 - - - 365 - - - @@ -2362,6 +2357,35 @@ Right click for insert and delete options. + + + + Age of last upload less than: + + + LotW_days_since_upload_spin_box + + + + + + + <html><head/><body><p>Adjust this spin box to set the age threshold of LotW user's last upload date that is accepted as a current LotW user.</p></body></html> + + + days + + + 0 + + + 9999 + + + 365 + + + @@ -2469,7 +2493,7 @@ Right click for insert and delete options. - Special operating activity: Generation of FT8 and MSK144 messages + Special operating activity: Generation of FT4, FT8, and MSK144 messages true @@ -2556,7 +2580,7 @@ Right click for insert and delete options. <html><head/><body><p>ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html> - ARRL RTTY Roundup + RTTY Roundup messages special_op_activity_button_group @@ -2821,6 +2845,48 @@ Right click for insert and delete options. + + + + + 0 + 50 + + + + Waterfall spectra + + + + + 10 + 20 + 91 + 17 + + + + Low sidelobes + + + true + + + + + + 120 + 20 + 92 + 17 + + + + Most sensitive + + + + @@ -3036,13 +3102,13 @@ Right click for insert and delete options. - - - - + + + + diff --git a/DXLabSuiteCommanderTransceiver.cpp b/DXLabSuiteCommanderTransceiver.cpp index 4e9270cfe..d745ec17f 100644 --- a/DXLabSuiteCommanderTransceiver.cpp +++ b/DXLabSuiteCommanderTransceiver.cpp @@ -127,7 +127,7 @@ int DXLabSuiteCommanderTransceiver::do_start () throw error {tr ("DX Lab Suite Commander didn't respond correctly reading frequency: ") + reply}; } - poll (); + do_poll (); return resolution; } @@ -247,7 +247,7 @@ void DXLabSuiteCommanderTransceiver::do_mode (MODE m) update_mode (m); } -void DXLabSuiteCommanderTransceiver::poll () +void DXLabSuiteCommanderTransceiver::do_poll () { #if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS bool quiet {false}; diff --git a/DXLabSuiteCommanderTransceiver.hpp b/DXLabSuiteCommanderTransceiver.hpp index b02fbef12..1196678b8 100644 --- a/DXLabSuiteCommanderTransceiver.hpp +++ b/DXLabSuiteCommanderTransceiver.hpp @@ -39,7 +39,7 @@ protected: void do_mode (MODE) override; void do_ptt (bool on) override; - void poll () override; + void do_poll () override; private: MODE get_mode (bool no_debug = false); diff --git a/Darwin/Info.plist.in b/Darwin/Info.plist.in index 830975da5..d2e943fe5 100644 --- a/Darwin/Info.plist.in +++ b/Darwin/Info.plist.in @@ -38,5 +38,7 @@ True NSRequiresAquaSystemAppearance + NSMicrophoneUsageDescription + This app requires microphone access to receive signals. diff --git a/Detector.cpp b/Detector.cpp index 69a10f5e8..05a631b13 100644 --- a/Detector.cpp +++ b/Detector.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "commons.h" #include "moc_Detector.cpp" @@ -10,7 +11,7 @@ extern "C" { void fil4_(qint16*, qint32*, qint16*, qint32*); } -Detector::Detector (unsigned frameRate, unsigned periodLengthInSeconds, +Detector::Detector (unsigned frameRate, double periodLengthInSeconds, unsigned downSampleFactor, QObject * parent) : AudioDevice (parent) , m_frameRate (frameRate) @@ -54,12 +55,14 @@ void Detector::clear () qint64 Detector::writeData (char const * data, qint64 maxSize) { - int ns=secondInPeriod(); - if(ns < m_ns) { // When ns has wrapped around to zero, restart the buffers + static unsigned mstr0=999999; + qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; + unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time + if(mstr < mstr0) { //When mstr has wrapped around to 0, restart the buffer dec_data.params.kin = 0; m_bufferPos = 0; } - m_ns=ns; + mstr0=mstr; // no torn frames Q_ASSERT (!(maxSize % static_cast (bytesPerFrame ()))); @@ -72,7 +75,7 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) if (framesAccepted < static_cast (maxSize / bytesPerFrame ())) { qDebug () << "dropped " << maxSize / bytesPerFrame () - framesAccepted << " frames of data on the floor!" - << dec_data.params.kin << ns; + << dec_data.params.kin << mstr; } for (unsigned remaining = framesAccepted; remaining; ) { @@ -120,13 +123,3 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) return maxSize; // we drop any data past the end of the buffer on // the floor until the next period starts } - -unsigned Detector::secondInPeriod () const -{ - // we take the time of the data as the following assuming no latency - // delivering it to us (not true but close enough for us) - qint64 now (QDateTime::currentMSecsSinceEpoch ()); - - unsigned secondInToday ((now % 86400000LL) / 1000); - return secondInToday % m_period; -} diff --git a/Detector.hpp b/Detector.hpp index d5e5b0a38..4d584c130 100644 --- a/Detector.hpp +++ b/Detector.hpp @@ -22,9 +22,10 @@ public: // // the samplesPerFFT argument is the number after down sampling // - Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned downSampleFactor = 4u, QObject * parent = 0); + Detector (unsigned frameRate, double periodLengthInSeconds, unsigned downSampleFactor = 4u, + QObject * parent = 0); - void setTRPeriod(unsigned p) {m_period=p;} + void setTRPeriod(double p) {m_period=p;} bool reset () override; Q_SIGNAL void framesWritten (qint64) const; @@ -40,10 +41,9 @@ protected: private: void clear (); // discard buffer contents - unsigned secondInPeriod () const; unsigned m_frameRate; - unsigned m_period; + double m_period; unsigned m_downSampleFactor; qint32 m_samplesPerFFT; // after any down sampling qint32 m_ns; diff --git a/EmulateSplitTransceiver.cpp b/EmulateSplitTransceiver.cpp index 7e84919e2..c42436db0 100644 --- a/EmulateSplitTransceiver.cpp +++ b/EmulateSplitTransceiver.cpp @@ -1,5 +1,7 @@ #include "EmulateSplitTransceiver.hpp" +#include "moc_EmulateSplitTransceiver.cpp" + EmulateSplitTransceiver::EmulateSplitTransceiver (std::unique_ptr wrapped, QObject * parent) : Transceiver {parent} , wrapped_ {std::move (wrapped)} diff --git a/EmulateSplitTransceiver.hpp b/EmulateSplitTransceiver.hpp index 210a37b71..d373c020e 100644 --- a/EmulateSplitTransceiver.hpp +++ b/EmulateSplitTransceiver.hpp @@ -27,6 +27,8 @@ class EmulateSplitTransceiver final : public Transceiver { + Q_OBJECT + public: // takes ownership of wrapped Transceiver explicit EmulateSplitTransceiver (std::unique_ptr wrapped, diff --git a/HRDTransceiver.cpp b/HRDTransceiver.cpp index 3b9f90e23..596f0ba27 100644 --- a/HRDTransceiver.cpp +++ b/HRDTransceiver.cpp @@ -19,6 +19,8 @@ namespace int constexpr yaesu_delay {250}; } +#include "moc_HRDTransceiver.cpp" + void HRDTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id) { (*registry)[HRD_transceiver_name] = TransceiverFactory::Capabilities (id, TransceiverFactory::Capabilities::network, true, true /* maybe */); @@ -885,7 +887,7 @@ bool HRDTransceiver::is_button_checked (int button_index, bool no_debug) return "1" == reply; } -void HRDTransceiver::poll () +void HRDTransceiver::do_poll () { #if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS bool quiet {false}; diff --git a/HRDTransceiver.hpp b/HRDTransceiver.hpp index e17134d53..2f563df6f 100644 --- a/HRDTransceiver.hpp +++ b/HRDTransceiver.hpp @@ -27,6 +27,8 @@ class QByteArray; class HRDTransceiver final : public PollingTransceiver { + Q_OBJECT + public: static void register_transceivers (TransceiverFactory::Transceivers *, int id); @@ -48,7 +50,7 @@ protected: void do_ptt (bool on) override; // Implement the PollingTransceiver interface. - void poll () override; + void do_poll () override; private: QString send_command (QString const&, bool no_debug = false, bool prepend_context = true, bool recurse = false); diff --git a/HamlibTransceiver.cpp b/HamlibTransceiver.cpp index f2e55bb4b..da0623e22 100644 --- a/HamlibTransceiver.cpp +++ b/HamlibTransceiver.cpp @@ -632,7 +632,7 @@ int HamlibTransceiver::do_start () resolution = -1; // best guess } - poll (); + do_poll (); TRACE_CAT ("HamlibTransceiver", "exit" << state () << "reversed =" << reversed_ << "resolution = " << resolution); return resolution; @@ -898,7 +898,7 @@ void HamlibTransceiver::do_mode (MODE mode) update_mode (mode); } -void HamlibTransceiver::poll () +void HamlibTransceiver::do_poll () { #if !WSJT_TRACE_CAT_POLLS #if defined (NDEBUG) diff --git a/HamlibTransceiver.hpp b/HamlibTransceiver.hpp index c8c0f74d7..bcc040d23 100644 --- a/HamlibTransceiver.hpp +++ b/HamlibTransceiver.hpp @@ -21,9 +21,9 @@ extern "C" class HamlibTransceiver final : public PollingTransceiver { - Q_OBJECT; // for translation context + Q_OBJECT // for translation context - public: +public: static void register_transceivers (TransceiverFactory::Transceivers *); static void unregister_transceivers (); @@ -40,7 +40,7 @@ class HamlibTransceiver final void do_mode (MODE) override; void do_ptt (bool) override; - void poll () override; + void do_poll () override; void error_check (int ret_code, QString const& doing) const; void set_conf (char const * item, char const * value); diff --git a/INSTALL b/INSTALL index 4f6e85b78..42169fb38 100644 --- a/INSTALL +++ b/INSTALL @@ -30,13 +30,13 @@ Mac". Qt v5, preferably v5.5 or later is required to build WSJT-X. -Qt v5 multimedia support and serial port is necessary as well as the -core Qt v5 components, normally installing the Qt multimedia -development package and Qt serialport development package are -sufficient to pull in all the required Qt components and dependants as -a single transaction. On some systems the Qt multimedia plugin -component is separate in the distribution repository an it may also -need installing. +Qt v5 multimedia support, serial port, and Linguist is necessary as +well as the core Qt v5 components, normally installing the Qt +multimedia development, Qt serialport development packages, and the Qt +Linguist packages are sufficient to pull in all the required Qt +components and dependants as a single transaction. On some systems +the Qt multimedia plugin component is separate in the distribution +repository an it may also need installing. The single precision FFTW v3 library libfftw3f is required along with the libfftw library development package. Normally installing the @@ -256,47 +256,6 @@ The above commands will build hamlib and install it into ~/hamlib-prefix. If `make install-strip` fails, try `make install`. -Qt --- - -NOTE: As of Qt v5.4 building Qt from source on Mac OS X is no longer -necessary since the Qt team have switched to using the modern libc++ -Standard C++ Library for all distributable run time -components. Instead you may simply download a binary installer for OS -X 64-bit. The binary installer is here: - - http://www.qt.io/download - -The binary Qt distributions prior to Qt v5.4 from -http://www.qt.io/download unfortunately are built to use the libstdc++ -C++ support library, WSJT-X uses a less geriatric C++ dialect which -uses the libc++ C++ support library. This means that you need to -build Qt from sources. This is not difficult but does take some time. - -Download the Qt source tarball from -http://www.qt.io/download-open-source/, the link is about half way -down the page, you want the full sources tar ball shown as a 'tar.gz' -link. - -Unpack the sources and cd into the top level directory then type: - -$ ./configure -prefix ~/local/qt-macx-clang -opensource \ - -confirm-license -platform macx-clang -silent -nomake tests \ - -nomake examples -sdk macosx10.10 -skip qtwebkit \ - -skip qtwebkit-examples -skip qtquick1 -skip qtconnectivity \ - -skip qtlocation -skip qtsensors -skip qtscript \ - -skip qtwebsockets -skip qtwebengine -skip qtwebchannel \ - -skip qtwayland -skip qtquickcontrols -skip qtdeclarative \ - -skip qtxmlpatterns -skip qtenginio -$ make -j4 -$ make install - -If you are building on 10.8 or don't have the 10.10 Mac SDK (Xcode 6) -available, you can substitute '-sdk macosx10.9' above. - -The build above will take a few hours to complete. - - CMake ----- Although CMake is available via MacPorts I prefer to use the binary @@ -328,6 +287,13 @@ $ sudo chgrp wheel /usr/local/bin and then retry the install command. +Qt +-- + +Download the latest on-line installer package from the Qt web site and +isntall the latest Qt stable version development package. + + WSJT-X ------ First fetch the source from the repository: @@ -411,4 +377,4 @@ $ cmake --build . --target install 73 Bill -G4WJS. \ No newline at end of file +G4WJS. diff --git a/LotWUsers.cpp b/LotWUsers.cpp index 877e70549..fd1b5746c 100644 --- a/LotWUsers.cpp +++ b/LotWUsers.cpp @@ -42,11 +42,12 @@ public: { } - void load (QString const& url, bool forced_fetch) + void load (QString const& url, bool fetch, bool forced_fetch) { - auto csv_file_name = csv_file_.fileName (); abort (); // abort any active download - if (!QFileInfo::exists (csv_file_name) || forced_fetch) + auto csv_file_name = csv_file_.fileName (); + auto exists = QFileInfo::exists (csv_file_name); + if (fetch && (!exists || forced_fetch)) { current_url_.setUrl (url); if (current_url_.isValid () && !QSslSocket::supportsSsl ()) @@ -58,8 +59,11 @@ public: } else { - // load the database asynchronously - future_load_ = std::async (std::launch::async, &LotWUsers::impl::load_dictionary, this, csv_file_name); + if (exists) + { + // load the database asynchronously + future_load_ = std::async (std::launch::async, &LotWUsers::impl::load_dictionary, this, csv_file_name); + } } } @@ -254,9 +258,9 @@ void LotWUsers::set_local_file_path (QString const& path) m_->csv_file_.setFileName (path); } -void LotWUsers::load (QString const& url, bool force_download) +void LotWUsers::load (QString const& url, bool fetch, bool force_download) { - m_->load (url, force_download); + m_->load (url, fetch, force_download); } void LotWUsers::set_age_constraint (qint64 uploaded_since_days) diff --git a/LotWUsers.hpp b/LotWUsers.hpp index e088b151e..238c57402 100644 --- a/LotWUsers.hpp +++ b/LotWUsers.hpp @@ -23,7 +23,7 @@ public: void set_local_file_path (QString const&); - Q_SLOT void load (QString const& url, bool force_download = false); + Q_SLOT void load (QString const& url, bool fetch = true, bool force_download = false); Q_SLOT void set_age_constraint (qint64 uploaded_since_days); // returns true if the specified call sign 'call' has uploaded their diff --git a/MessageClient.cpp b/MessageClient.cpp index 873ba1fd4..ddf269564 100644 --- a/MessageClient.cpp +++ b/MessageClient.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,7 @@ public: impl (QString const& id, QString const& version, QString const& revision, port_type server_port, MessageClient * self) : self_ {self} + , enabled_ {false} , id_ {id} , version_ {version} , revision_ {revision} @@ -79,6 +81,7 @@ public: Q_SLOT void host_info_results (QHostInfo); MessageClient * self_; + bool enabled_; QString id_; QString version_; QString revision_; @@ -152,7 +155,7 @@ void MessageClient::impl::parse_message (QByteArray const& msg) // message format is described in NetworkMessage.hpp // NetworkMessage::Reader in {msg}; - if (OK == check_status (in) && id_ == in.id ()) // OK and for us + if (OK == check_status (in)) { if (schema_ < in.schema ()) // one time record of server's // negotiated schema @@ -160,6 +163,12 @@ void MessageClient::impl::parse_message (QByteArray const& msg) schema_ = in.schema (); } + if (!enabled_) + { + TRACE_UDP ("message processing disabled for id:" << in.id ()); + return; + } + // // message format is described in NetworkMessage.hpp // @@ -200,6 +209,15 @@ void MessageClient::impl::parse_message (QByteArray const& msg) } break; + case NetworkMessage::Close: + TRACE_UDP ("Close"); + if (check_status (in) != Fail) + { + last_message_.clear (); + Q_EMIT self_->close (); + } + break; + case NetworkMessage::Replay: TRACE_UDP ("Replay"); if (check_status (in) != Fail) @@ -261,6 +279,42 @@ void MessageClient::impl::parse_message (QByteArray const& msg) } break; + case NetworkMessage::SwitchConfiguration: + { + QByteArray configuration_name; + in >> configuration_name; + TRACE_UDP ("Switch Configuration name:" << configuration_name); + if (check_status (in) != Fail) + { + Q_EMIT self_->switch_configuration (QString::fromUtf8 (configuration_name)); + } + } + break; + + case NetworkMessage::Configure: + { + QByteArray mode; + quint32 frequency_tolerance; + QByteArray submode; + bool fast_mode {false}; + quint32 tr_period {std::numeric_limits::max ()}; + quint32 rx_df {std::numeric_limits::max ()}; + QByteArray dx_call; + QByteArray dx_grid; + bool generate_messages {false}; + in >> mode >> frequency_tolerance >> submode >> fast_mode >> tr_period >> rx_df + >> dx_call >> dx_grid >> generate_messages; + TRACE_UDP ("Configure mode:" << mode << "frequency tolerance:" << frequency_tolerance << "submode:" << submode << "fast mode:" << fast_mode << "T/R period:" << tr_period << "rx df:" << rx_df << "dx call:" << dx_call << "dx grid:" << dx_grid << "generate messages:" << generate_messages); + if (check_status (in) != Fail) + { + Q_EMIT self_->configure (QString::fromUtf8 (mode), frequency_tolerance + , QString::fromUtf8 (submode), fast_mode, tr_period, rx_df + , QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid) + , generate_messages); + } + } + break; + default: // Ignore // @@ -438,13 +492,20 @@ void MessageClient::add_blocked_destination (QHostAddress const& a) } } +void MessageClient::enable (bool flag) +{ + m_->enabled_ = flag; +} + void MessageClient::status_update (Frequency f, QString const& mode, QString const& dx_call , QString const& report, QString const& tx_mode , bool tx_enabled, bool transmitting, bool decoding - , qint32 rx_df, qint32 tx_df, QString const& de_call + , quint32 rx_df, quint32 tx_df, QString const& de_call , QString const& de_grid, QString const& dx_grid , bool watchdog_timeout, QString const& sub_mode - , bool fast_mode, quint8 special_op_mode) + , bool fast_mode, quint8 special_op_mode + , quint32 frequency_tolerance, quint32 tr_period + , QString const& configuration_name) { if (m_->server_port_ && !m_->server_string_.isEmpty ()) { @@ -453,8 +514,8 @@ void MessageClient::status_update (Frequency f, QString const& mode, QString con out << f << mode.toUtf8 () << dx_call.toUtf8 () << report.toUtf8 () << tx_mode.toUtf8 () << tx_enabled << transmitting << decoding << rx_df << tx_df << de_call.toUtf8 () << de_grid.toUtf8 () << dx_grid.toUtf8 () << watchdog_timeout << sub_mode.toUtf8 () - << fast_mode << special_op_mode; - TRACE_UDP ("frequency:" << f << "mode:" << mode << "DX:" << dx_call << "report:" << report << "Tx mode:" << tx_mode << "tx_enabled:" << tx_enabled << "Tx:" << transmitting << "decoding:" << decoding << "Rx df:" << rx_df << "Tx df:" << tx_df << "DE:" << de_call << "DE grid:" << de_grid << "DX grid:" << dx_grid << "w/d t/o:" << watchdog_timeout << "sub_mode:" << sub_mode << "fast mode:" << fast_mode << "spec op mode:" << special_op_mode); + << fast_mode << special_op_mode << frequency_tolerance << tr_period << configuration_name.toUtf8 (); + TRACE_UDP ("frequency:" << f << "mode:" << mode << "DX:" << dx_call << "report:" << report << "Tx mode:" << tx_mode << "tx_enabled:" << tx_enabled << "Tx:" << transmitting << "decoding:" << decoding << "Rx df:" << rx_df << "Tx df:" << tx_df << "DE:" << de_call << "DE grid:" << de_grid << "DX grid:" << dx_grid << "w/d t/o:" << watchdog_timeout << "sub_mode:" << sub_mode << "fast mode:" << fast_mode << "spec op mode:" << special_op_mode << "frequency tolerance:" << frequency_tolerance << "T/R period:" << tr_period << "configuration name:" << configuration_name); m_->send_message (out, message); } } @@ -527,7 +588,7 @@ void MessageClient::logged_ADIF (QByteArray const& ADIF_record) { QByteArray message; NetworkMessage::Builder out {&message, NetworkMessage::LoggedADIF, m_->id_, m_->schema_}; - QByteArray ADIF {"\n3.0.7\nWSJT-X\n\n" + ADIF_record + " "}; + QByteArray ADIF {"\n3.1.0\nWSJT-X\n\n" + ADIF_record + " "}; out << ADIF; TRACE_UDP ("ADIF:" << ADIF); m_->send_message (out, message); diff --git a/MessageClient.hpp b/MessageClient.hpp index ca5f02037..20f39b019 100644 --- a/MessageClient.hpp +++ b/MessageClient.hpp @@ -47,12 +47,16 @@ public: // change the server port messages are sent to Q_SLOT void set_server_port (port_type server_port = 0u); + // enable incoming messages + Q_SLOT void enable (bool); + // outgoing messages Q_SLOT void status_update (Frequency, QString const& mode, QString const& dx_call, QString const& report , QString const& tx_mode, bool tx_enabled, bool transmitting, bool decoding - , qint32 rx_df, qint32 tx_df, QString const& de_call, QString const& de_grid + , quint32 rx_df, quint32 tx_df, QString const& de_call, QString const& de_grid , QString const& dx_grid, bool watchdog_timeout, QString const& sub_mode - , bool fast_mode, quint8 special_op_mode); + , bool fast_mode, quint8 special_op_mode, quint32 frequency_tolerance + , quint32 tr_period, QString const& configuration_name); Q_SLOT void decode (bool is_new, QTime time, qint32 snr, float delta_time, quint32 delta_frequency , QString const& mode, QString const& message, bool low_confidence , bool off_air); @@ -89,6 +93,10 @@ public: Q_SIGNAL void reply (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode , QString const& message_text, bool low_confidence, quint8 modifiers); + // this signal is emitted if the server has requested this client to + // close down gracefully + Q_SIGNAL void close (); + // this signal is emitted if the server has requested a replay of // all decodes Q_SIGNAL void replay (); @@ -105,6 +113,16 @@ public: // callsign request for the specified call Q_SIGNAL void highlight_callsign (QString const& callsign, QColor const& bg, QColor const& fg, bool last_only); + // this signal is emitted if the server has requested a + // configuration switch + Q_SIGNAL void switch_configuration (QString const& configuration_name); + + // this signal is emitted if the server has requested a + // configuration change + Q_SIGNAL void configure (QString const& mode, quint32 frequency_tolerance, QString const& submode + , bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call + , QString const& dx_grid, bool generate_messages); + // this signal is emitted when network errors occur or if a host // lookup fails Q_SIGNAL void error (QString const&) const; diff --git a/MessageServer.cpp b/MessageServer.cpp index dadf3d984..07b2fb429 100644 --- a/MessageServer.cpp +++ b/MessageServer.cpp @@ -1,6 +1,7 @@ #include "MessageServer.hpp" #include +#include #include #include @@ -16,6 +17,11 @@ #include "moc_MessageServer.cpp" +namespace +{ + auto quint32_max = std::numeric_limits::max (); +} + class MessageServer::impl : public QUdpSocket { @@ -238,8 +244,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s bool tx_enabled {false}; bool transmitting {false}; bool decoding {false}; - qint32 rx_df {-1}; - qint32 tx_df {-1}; + quint32 rx_df {quint32_max}; + quint32 tx_df {quint32_max}; QByteArray de_call; QByteArray de_grid; QByteArray dx_grid; @@ -247,9 +253,12 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s QByteArray sub_mode; bool fast_mode {false}; quint8 special_op_mode {0}; + quint32 frequency_tolerance {quint32_max}; + quint32 tr_period {quint32_max}; + QByteArray configuration_name; in >> f >> mode >> dx_call >> report >> tx_mode >> tx_enabled >> transmitting >> decoding >> rx_df >> tx_df >> de_call >> de_grid >> dx_grid >> watchdog_timeout >> sub_mode - >> fast_mode >> special_op_mode; + >> fast_mode >> special_op_mode >> frequency_tolerance >> tr_period >> configuration_name; if (check_status (in) != Fail) { Q_EMIT self_->status_update (id, f, QString::fromUtf8 (mode), QString::fromUtf8 (dx_call) @@ -258,7 +267,8 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s , QString::fromUtf8 (de_call), QString::fromUtf8 (de_grid) , QString::fromUtf8 (dx_grid), watchdog_timeout , QString::fromUtf8 (sub_mode), fast_mode - , special_op_mode); + , special_op_mode, frequency_tolerance, tr_period + , QString::fromUtf8 (configuration_name)); } } break; @@ -493,6 +503,17 @@ void MessageServer::replay (QString const& id) } } +void MessageServer::close (QString const& id) +{ + auto iter = m_->clients_.find (id); + if (iter != std::end (m_->clients_)) + { + QByteArray message; + NetworkMessage::Builder out {&message, NetworkMessage::Close, id, (*iter).negotiated_schema_number_}; + m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); + } +} + void MessageServer::halt_tx (QString const& id, bool auto_only) { auto iter = m_->clients_.find (id); @@ -541,3 +562,30 @@ void MessageServer::highlight_callsign (QString const& id, QString const& callsi m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); } } + +void MessageServer::switch_configuration (QString const& id, QString const& configuration_name) +{ + auto iter = m_->clients_.find (id); + if (iter != std::end (m_->clients_)) + { + QByteArray message; + NetworkMessage::Builder out {&message, NetworkMessage::SwitchConfiguration, id, (*iter).negotiated_schema_number_}; + out << configuration_name.toUtf8 (); + m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); + } +} + +void MessageServer::configure (QString const& id, QString const& mode, quint32 frequency_tolerance + , QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df + , QString const& dx_call, QString const& dx_grid, bool generate_messages) +{ + auto iter = m_->clients_.find (id); + if (iter != std::end (m_->clients_)) + { + QByteArray message; + NetworkMessage::Builder out {&message, NetworkMessage::Configure, id, (*iter).negotiated_schema_number_}; + out << mode.toUtf8 () << frequency_tolerance << submode.toUtf8 () << fast_mode << tr_period << rx_df + << dx_call.toUtf8 () << dx_grid.toUtf8 () << generate_messages; + m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); + } +} diff --git a/MessageServer.hpp b/MessageServer.hpp index 12377bef9..f59c21fe0 100644 --- a/MessageServer.hpp +++ b/MessageServer.hpp @@ -52,6 +52,9 @@ public: Q_SLOT void reply (QString const& id, QTime time, qint32 snr, float delta_time, quint32 delta_frequency , QString const& mode, QString const& message, bool low_confidence, quint8 modifiers); + // ask the client with identification 'id' to close down gracefully + Q_SLOT void close (QString const& id); + // ask the client with identification 'id' to replay all decodes Q_SLOT void replay (QString const& id); @@ -72,15 +75,25 @@ public: , QColor const& bg = QColor {}, QColor const& fg = QColor {} , bool last_only = false); + // ask the client with identification 'id' to switch to + // configuration 'configuration_name' + Q_SLOT void switch_configuration (QString const& id, QString const& configuration_name); + + // ask the client with identification 'id' to change configuration + Q_SLOT void configure (QString const& id, QString const& mode, quint32 frequency_tolerance + , QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df + , QString const& dx_call, QString const& dx_grid, bool generate_messages); + // the following signals are emitted when a client broadcasts the // matching message Q_SIGNAL void client_opened (QString const& id, QString const& version, QString const& revision); Q_SIGNAL void status_update (QString const& id, Frequency, QString const& mode, QString const& dx_call , QString const& report, QString const& tx_mode, bool tx_enabled - , bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df + , bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df , QString const& de_call, QString const& de_grid, QString const& dx_grid , bool watchdog_timeout, QString const& sub_mode, bool fast_mode - , quint8 special_op_mode); + , quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period + , QString const& configuration_name); Q_SIGNAL void client_closed (QString const& id); Q_SIGNAL void decode (bool is_new, QString const& id, QTime time, qint32 snr, float delta_time , quint32 delta_frequency, QString const& mode, QString const& message diff --git a/MetaDataRegistry.cpp b/MetaDataRegistry.cpp index bf2aab5d4..e66a43008 100644 --- a/MetaDataRegistry.cpp +++ b/MetaDataRegistry.cpp @@ -14,16 +14,35 @@ #include "WFPalette.hpp" #include "models/IARURegions.hpp" #include "models/DecodeHighlightingModel.hpp" -#include "widgets/FrequencyLineEdit.hpp" +#include "widgets/DateTimeEdit.hpp" -QItemEditorFactory * item_editor_factory () +namespace { - static QItemEditorFactory * our_item_editor_factory = new QItemEditorFactory; - return our_item_editor_factory; + class ItemEditorFactory final + : public QItemEditorFactory + { + public: + ItemEditorFactory () + : default_factory_ {QItemEditorFactory::defaultFactory ()} + { + } + + QWidget * createEditor (int user_type, QWidget * parent) const override + { + auto editor = QItemEditorFactory::createEditor (user_type, parent); + return editor ? editor : default_factory_->createEditor (user_type, parent); + } + + private: + QItemEditorFactory const * default_factory_; + }; } void register_types () { + auto item_editor_factory = new ItemEditorFactory; + QItemEditorFactory::setDefaultFactory (item_editor_factory); + // types in Radio.hpp are registered in their own translation unit // as they are needed in the wsjtx_udp shared library too @@ -31,9 +50,7 @@ void register_types () // used as signal/slot connection arguments since the new Qt 5.5 // Q_ENUM macro only seems to register the unqualified name - item_editor_factory ()->registerEditor (qMetaTypeId (), new QStandardItemEditorCreator ()); - //auto frequency_delta_type_id = qRegisterMetaType ("FrequencyDelta"); - item_editor_factory ()->registerEditor (qMetaTypeId (), new QStandardItemEditorCreator ()); + item_editor_factory->registerEditor (qMetaTypeId (), new QStandardItemEditorCreator ()); // Frequency list model qRegisterMetaTypeStreamOperators ("Item_v2"); diff --git a/MetaDataRegistry.hpp b/MetaDataRegistry.hpp index 43000d201..8bf3c80dc 100644 --- a/MetaDataRegistry.hpp +++ b/MetaDataRegistry.hpp @@ -1,9 +1,6 @@ #ifndef META_DATA_REGISTRY_HPP__ #define META_DATA_REGISTRY_HPP__ -class QItemEditorFactory; - -QItemEditorFactory * item_editor_factory (); void register_types (); #endif diff --git a/Modulator.cpp b/Modulator.cpp index a7564f6cf..4d0171770 100644 --- a/Modulator.cpp +++ b/Modulator.cpp @@ -25,15 +25,15 @@ double constexpr Modulator::m_twoPi; // unsigned m_nspd=1.2*48000.0/wpm; // m_nspd=3072; //18.75 WPM -Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, +Modulator::Modulator (unsigned frameRate, double periodLengthInSeconds, QObject * parent) : AudioDevice {parent} , m_quickClose {false} , m_phi {0.0} , m_toneSpacing {0.0} , m_fSpread {0.0} - , m_frameRate {frameRate} , m_period {periodLengthInSeconds} + , m_frameRate {frameRate} , m_state {Idle} , m_tuning {false} , m_cwLevel {false} @@ -45,19 +45,15 @@ Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, void Modulator::start (unsigned symbolsLength, double framesPerSymbol, double frequency, double toneSpacing, SoundOutput * stream, Channel channel, - bool synchronize, bool fastMode, double dBSNR, int TRperiod) + bool synchronize, bool fastMode, double dBSNR, double TRperiod) { Q_ASSERT (stream); // Time according to this computer which becomes our base time qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; + unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time - if (m_state != Idle) - { - stop (); - } - + if(m_state != Idle) stop(); m_quickClose = false; - m_symbolsLength = symbolsLength; m_isym0 = std::numeric_limits::max (); // big number m_frequency0 = 0.; @@ -69,30 +65,34 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol, m_toneSpacing = toneSpacing; m_bFastMode=fastMode; m_TRperiod=TRperiod; - unsigned delay_ms = 1920 == m_nsps && 15 == m_period ? 500 : 1000; + unsigned delay_ms=1000; + if(m_nsps==1920) delay_ms=500; //FT8 + if(m_nsps==576) delay_ms=300; //FT4 - // noise generator parameters +// noise generator parameters if (m_addNoise) { m_snr = qPow (10.0, 0.05 * (dBSNR - 6.0)); m_fac = 3000.0; if (m_snr > 1.0) m_fac = 3000.0 / m_snr; } - unsigned mstr = ms0 % (1000 * m_period); // ms in period - - // round up to an exact portion of a second that allows for startup - // delays +// round up to an exact portion of a second that allows for startup delays m_ic = (mstr / delay_ms) * m_frameRate * delay_ms / 1000; if(m_bFastMode) m_ic=0; m_silentFrames = 0; - // calculate number of silent frames to send, so that audio will start at - // the nominal time "delay_ms" into the Tx sequence. +// calculate number of silent frames to send, so that audio will start at +// the nominal time "delay_ms" into the Tx sequence. if (synchronize && !m_tuning && !m_bFastMode) { m_silentFrames = m_ic + m_frameRate / (1000 / delay_ms) - (mstr * (m_frameRate / 1000)); } +// qDebug() << "aa" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.zzz") +// << m_ic << m_silentFrames << m_silentFrames/48000.0 +// << mstr << fmod(double(ms0),1000.0*m_period); + + initialize (QIODevice::ReadOnly, channel); Q_EMIT stateChanged ((m_state = (synchronize && m_silentFrames) ? Synchronizing : Active)); @@ -149,6 +149,8 @@ qint64 Modulator::readData (char * data, qint64 maxSize) qint16 * end (samples + numFrames * (bytesPerFrame () / sizeof (qint16))); qint64 framesGenerated (0); +// if(m_ic==0) qDebug() << "Modulator::readData" << 0.001*(QDateTime::currentMSecsSinceEpoch() % (1000*m_TRperiod)); + switch (m_state) { case Synchronizing: @@ -170,17 +172,19 @@ qint64 Modulator::readData (char * data, qint64 maxSize) case Active: { unsigned int isym=0; -// qDebug() << "Mod A" << m_toneSpacing << m_ic; + if(!m_tuning) isym=m_ic/(4.0*m_nsps); // Actual fsample=48000 bool slowCwId=((isym >= m_symbolsLength) && (icw[0] > 0)) && (!m_bFastMode); - if(m_TRperiod==3) slowCwId=false; + if(m_TRperiod==3.0) slowCwId=false; bool fastCwId=false; static bool bCwId=false; qint64 ms = QDateTime::currentMSecsSinceEpoch(); - float tsec=0.001*(ms % (1000*m_TRperiod)); - if(m_bFastMode and (icw[0]>0) and (tsec>(m_TRperiod-5.0))) fastCwId=true; + float tsec=0.001*(ms % int(1000*m_TRperiod)); + if(m_bFastMode and (icw[0]>0) and (tsec > (m_TRperiod-5.0))) fastCwId=true; if(!m_bFastMode) m_nspd=2560; // 22.5 WPM +// qDebug() << "Mod A" << m_ic << isym << tsec; + if(slowCwId or fastCwId) { // Transmit CW ID? m_dphi = m_twoPi*m_frequency/m_frameRate; if(m_bFastMode and !bCwId) { @@ -247,15 +251,15 @@ qint64 Modulator::readData (char * data, qint64 maxSize) i1= m_symbolsLength * 4.0 * m_nsps; } if(m_bFastMode and !m_tuning) { - i1=m_TRperiod*48000 - 24000; + i1=m_TRperiod*48000.0 - 24000.0; i0=i1-816; } qint16 sample; + for (unsigned i = 0; i < numFrames && m_ic <= i1; ++i) { isym=0; - if(!m_tuning and m_TRperiod!=3) isym=m_ic / (4.0 * m_nsps); //Actual - //fsample=48000 + if(!m_tuning and m_TRperiod!=3.0) isym=m_ic/(4.0*m_nsps); //Actual fsample=48000 if(m_bFastMode) isym=isym%m_symbolsLength; if (isym != m_isym0 || m_frequency != m_frequency0) { if(itone[0]>=100) { @@ -267,8 +271,6 @@ qint64 Modulator::readData (char * data, qint64 maxSize) m_toneFrequency0=m_frequency + itone[isym]*m_toneSpacing; } } -// qDebug() << "Mod B" << m_bFastMode << m_ic << numFrames << isym << itone[isym] -// << m_toneFrequency0 << m_nsps; m_dphi = m_twoPi * m_toneFrequency0 / m_frameRate; m_isym0 = isym; m_frequency0 = m_frequency; //??? @@ -289,9 +291,12 @@ qint64 Modulator::readData (char * data, qint64 maxSize) if (m_ic > i1) m_amp = 0.0; sample=qRound(m_amp*qSin(m_phi)); - if(m_toneSpacing < 0) sample=qRound(m_amp*foxcom_.wave[m_ic]); -// if(m_ic < 100) qDebug() << "Mod C" << m_ic << m_amp << foxcom_.wave[m_ic] << sample; +//Here's where we transmit from a precomputed wave[] array: + if(!m_tuning and (m_toneSpacing < 0)) { + m_amp=32767.0; + sample=qRound(m_amp*foxcom_.wave[m_ic]); + } samples = load(postProcessSample(sample), samples); ++framesGenerated; @@ -308,7 +313,15 @@ qint64 Modulator::readData (char * data, qint64 maxSize) } m_frequency0 = m_frequency; - // done for this chunk - continue on next call +// done for this chunk - continue on next call + +// qDebug() << "Mod B" << m_ic << i1 << 0.001*(QDateTime::currentMSecsSinceEpoch() % (1000*m_TRperiod)); + + while (samples != end) // pad block with silence + { + samples = load (0, samples); + ++framesGenerated; + } return framesGenerated * bytesPerFrame (); } // fall through diff --git a/Modulator.hpp b/Modulator.hpp index 493b94bc3..3371cbe5e 100644 --- a/Modulator.hpp +++ b/Modulator.hpp @@ -23,7 +23,7 @@ class Modulator public: enum ModulatorState {Synchronizing, Active, Idle}; - Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent = nullptr); + Modulator (unsigned frameRate, double periodLengthInSeconds, QObject * parent = nullptr); void close () override; @@ -31,13 +31,14 @@ public: double frequency () const {return m_frequency;} bool isActive () const {return m_state != Idle;} void setSpread(double s) {m_fSpread=s;} - void setTRPeriod(unsigned p) {m_period=p;} + void setTRPeriod(double p) {m_period=p;} void set_nsym(int n) {m_symbolsLength=n;} + void set_ms0(qint64 ms) {m_ms0=ms;} Q_SLOT void start (unsigned symbolsLength, double framesPerSymbol, double frequency, double toneSpacing, SoundOutput *, Channel = Mono, bool synchronize = true, bool fastMode = false, - double dBSNR = 99., int TRperiod=60); + double dBSNR = 99., double TRperiod=60.0); Q_SLOT void stop (bool quick = false); Q_SLOT void tune (bool newState = true); Q_SLOT void setFrequency (double newFrequency) {m_frequency = newFrequency;} @@ -71,13 +72,14 @@ private: double m_fac; double m_toneSpacing; double m_fSpread; + double m_TRperiod; + double m_period; qint64 m_silentFrames; - qint32 m_TRperiod; + qint64 m_ms0; qint16 m_ramp; unsigned m_frameRate; - unsigned m_period; ModulatorState volatile m_state; bool volatile m_tuning; diff --git a/MultiSettings.cpp b/MultiSettings.cpp index f4798bc3f..29c686d3d 100644 --- a/MultiSettings.cpp +++ b/MultiSettings.cpp @@ -65,6 +65,8 @@ namespace class NameDialog final : public QDialog { + Q_OBJECT + public: explicit NameDialog (QString const& current_name, QStringList const& current_names, @@ -112,6 +114,8 @@ namespace class ExistingNameDialog final : public QDialog { + Q_OBJECT + public: explicit ExistingNameDialog (QStringList const& current_names, QWidget * parent = nullptr) : QDialog {parent} @@ -155,13 +159,16 @@ public: bool exit (); QSettings settings_; + QString current_; + + // switch to this configuration + void select_configuration (QString const& target_name); private: using Dictionary = QMap; // create a configuration maintenance sub menu - QMenu * create_sub_menu (QMainWindow * main_window, - QMenu * parent, + QMenu * create_sub_menu (QMenu * parent, QString const& menu_title, QActionGroup * = nullptr); @@ -171,32 +178,32 @@ private: // write the settings values from the dictionary to the current group void load_from (Dictionary const&, bool add_placeholder = true); - // switch to this configuration - void select_configuration (QMainWindow *, QMenu const *); - // clone this configuration - void clone_configuration (QMainWindow * main_window, QMenu *, QMenu const *); + void clone_configuration (QMenu *, QMenu const *); // update this configuration from another - void clone_into_configuration (QMainWindow *, QMenu const *); + void clone_into_configuration (QMenu const *); // reset configuration to default values - void reset_configuration (QMainWindow *, QMenu const *); + void reset_configuration (QMenu const *); // change configuration name - void rename_configuration (QMainWindow *, QMenu *); + void rename_configuration (QMenu *); // remove a configuration - void delete_configuration (QMainWindow *, QMenu *); + void delete_configuration (QMenu *); + + // action to take on restart + enum class RepositionType {unchanged, replace, save_and_replace}; + void restart (RepositionType); MultiSettings const * parent_; // required for emitting signals + QMainWindow * main_window_; bool name_change_emit_pending_; // delayed until menu built QFont original_font_; - QString current_; - // action to take on restart - enum class RepositionType {unchanged, replace, save_and_replace} reposition_type_; + RepositionType reposition_type_; Dictionary new_settings_; bool exit_flag_; // false means loop around with new // configuration @@ -263,6 +270,16 @@ void MultiSettings::create_menu_actions (QMainWindow * main_window, QMenu * menu m_->create_menu_actions (main_window, menu); } +void MultiSettings::select_configuration (QString const& name) +{ + m_->select_configuration (name); +} + +QString MultiSettings::configuration_name () const +{ + return m_->current_; +} + bool MultiSettings::exit () { return m_->exit (); @@ -271,6 +288,7 @@ bool MultiSettings::exit () MultiSettings::impl::impl (MultiSettings const * parent, QString const& config_name) : settings_ {settings_path (), QSettings::IniFormat} , parent_ {parent} + , main_window_ {nullptr} , name_change_emit_pending_ {true} , reposition_type_ {RepositionType::unchanged} , exit_flag_ {true} @@ -407,13 +425,14 @@ bool MultiSettings::impl::reposition () // and, reset void MultiSettings::impl::create_menu_actions (QMainWindow * main_window, QMenu * menu) { + main_window_ = main_window; auto const& current_group = settings_.group (); if (current_group.size ()) settings_.endGroup (); SettingsGroup alternatives {&settings_, multi_settings_root_group}; // get the current configuration name auto const& current_configuration_name = settings_.value (multi_settings_current_name_key, tr (default_string)).toString (); // add the default configuration sub menu - QMenu * default_menu = create_sub_menu (main_window, menu, current_configuration_name, configurations_group_); + QMenu * default_menu = create_sub_menu (menu, current_configuration_name, configurations_group_); // and set as the current configuration default_menu->menuAction ()->setChecked (true); @@ -423,7 +442,7 @@ void MultiSettings::impl::create_menu_actions (QMainWindow * main_window, QMenu // add all the other configurations for (auto const& configuration_name: available_configurations) { - create_sub_menu (main_window, menu, configuration_name, configurations_group_); + create_sub_menu (menu, configuration_name, configurations_group_); } if (current_group.size ()) settings_.beginGroup (current_group); @@ -446,8 +465,7 @@ bool MultiSettings::impl::exit () return reposition (); } -QMenu * MultiSettings::impl::create_sub_menu (QMainWindow * main_window, - QMenu * parent_menu, +QMenu * MultiSettings::impl::create_sub_menu (QMenu * parent_menu, QString const& menu_title, QActionGroup * action_group) { @@ -456,7 +474,7 @@ QMenu * MultiSettings::impl::create_sub_menu (QMainWindow * main_window, sub_menu->menuAction ()->setCheckable (true); // populate sub-menu actions before showing - connect (sub_menu, &QMenu::aboutToShow, [this, main_window, parent_menu, sub_menu] () { + connect (sub_menu, &QMenu::aboutToShow, [this, parent_menu, sub_menu] () { // depopulate before populating and showing because on Mac OS X // there is an issue with depopulating in QMenu::aboutToHide() // with connections being disconnected before they are actioned @@ -470,16 +488,16 @@ QMenu * MultiSettings::impl::create_sub_menu (QMainWindow * main_window, { auto select_action = new QAction {tr ("&Switch To"), this}; sub_menu->addAction (select_action); - connect (select_action, &QAction::triggered, [this, main_window, sub_menu] (bool) { - select_configuration (main_window, sub_menu); + connect (select_action, &QAction::triggered, [this, sub_menu] (bool) { + select_configuration (sub_menu->title ()); }); sub_menu->addSeparator (); } auto clone_action = new QAction {tr ("&Clone"), this}; sub_menu->addAction (clone_action); - connect (clone_action, &QAction::triggered, [this, main_window, parent_menu, sub_menu] (bool) { - clone_configuration (main_window, parent_menu, sub_menu); + connect (clone_action, &QAction::triggered, [this, parent_menu, sub_menu] (bool) { + clone_configuration (parent_menu, sub_menu); }); auto const& current_group = settings_.group (); @@ -489,29 +507,29 @@ QMenu * MultiSettings::impl::create_sub_menu (QMainWindow * main_window, { auto clone_into_action = new QAction {tr ("Clone &Into ..."), this}; sub_menu->addAction (clone_into_action); - connect (clone_into_action, &QAction::triggered, [this, main_window, sub_menu] (bool) { - clone_into_configuration (main_window, sub_menu); + connect (clone_into_action, &QAction::triggered, [this, sub_menu] (bool) { + clone_into_configuration (sub_menu); }); } if (current_group.size ()) settings_.beginGroup (current_group); auto reset_action = new QAction {tr ("R&eset"), this}; sub_menu->addAction (reset_action); - connect (reset_action, &QAction::triggered, [this, main_window, sub_menu] (bool) { - reset_configuration (main_window, sub_menu); + connect (reset_action, &QAction::triggered, [this, sub_menu] (bool) { + reset_configuration (sub_menu); }); auto rename_action = new QAction {tr ("&Rename ..."), this}; sub_menu->addAction (rename_action); - connect (rename_action, &QAction::triggered, [this, main_window, sub_menu] (bool) { - rename_configuration (main_window, sub_menu); + connect (rename_action, &QAction::triggered, [this, sub_menu] (bool) { + rename_configuration (sub_menu); }); if (!is_current) { auto delete_action = new QAction {tr ("&Delete"), this}; sub_menu->addAction (delete_action); - connect (delete_action, &QAction::triggered, [this, main_window, sub_menu] (bool) { - delete_configuration (main_window, sub_menu); + connect (delete_action, &QAction::triggered, [this, sub_menu] (bool) { + delete_configuration (sub_menu); }); } }); @@ -554,11 +572,9 @@ void MultiSettings::impl::load_from (Dictionary const& dictionary, bool add_plac settings_.sync (); } -void MultiSettings::impl::select_configuration (QMainWindow * main_window, QMenu const * menu) +void MultiSettings::impl::select_configuration (QString const& target_name) { - auto const& target_name = menu->title (); - - if (target_name != current_) + if (main_window_ && target_name != current_) { { auto const& current_group = settings_.group (); @@ -573,13 +589,11 @@ void MultiSettings::impl::select_configuration (QMainWindow * main_window, QMenu // and set up the restart current_ = target_name; Q_EMIT parent_->configurationNameChanged (unescape_ampersands (current_)); - reposition_type_ = RepositionType::save_and_replace; - exit_flag_ = false; - main_window->close (); + restart (RepositionType::save_and_replace); } } -void MultiSettings::impl::clone_configuration (QMainWindow * main_window, QMenu * parent_menu, QMenu const * menu) +void MultiSettings::impl::clone_configuration (QMenu * parent_menu, QMenu const * menu) { auto const& current_group = settings_.group (); if (current_group.size ()) settings_.endGroup (); @@ -612,12 +626,15 @@ void MultiSettings::impl::clone_configuration (QMainWindow * main_window, QMenu load_from (source_settings); // insert the new configuration sub menu in the parent menu - create_sub_menu (main_window, parent_menu, new_name, configurations_group_); + create_sub_menu (parent_menu, new_name, configurations_group_); if (current_group.size ()) settings_.beginGroup (current_group); } -void MultiSettings::impl::clone_into_configuration (QMainWindow * main_window, QMenu const * menu) +void MultiSettings::impl::clone_into_configuration (QMenu const * menu) { + Q_ASSERT (main_window_); + if (!main_window_) return; + auto const& current_group = settings_.group (); if (current_group.size ()) settings_.endGroup (); auto const& target_name = menu->title (); @@ -638,15 +655,16 @@ void MultiSettings::impl::clone_into_configuration (QMainWindow * main_window, Q } // pick a source configuration - ExistingNameDialog dialog {sources, main_window}; + ExistingNameDialog dialog {sources, main_window_}; if (sources.size () && (1 == sources.size () || QDialog::Accepted == dialog.exec ())) { QString source_name {1 == sources.size () ? sources.at (0) : dialog.name ()}; - if (MessageBox::Yes == MessageBox::query_message (main_window, - tr ("Clone Into Configuration"), - tr ("Confirm overwrite of all values for configuration \"%1\" with values from \"%2\"?") - .arg (unescape_ampersands (target_name)) - .arg (unescape_ampersands (source_name)))) + if (main_window_ + && MessageBox::Yes == MessageBox::query_message (main_window_, + tr ("Clone Into Configuration"), + tr ("Confirm overwrite of all values for configuration \"%1\" with values from \"%2\"?") + .arg (unescape_ampersands (target_name)) + .arg (unescape_ampersands (source_name)))) { // grab the data to clone from if (source_name == current_group_name) @@ -665,9 +683,7 @@ void MultiSettings::impl::clone_into_configuration (QMainWindow * main_window, Q if (target_name == current_) { // restart with new settings - reposition_type_ = RepositionType::replace; - exit_flag_ = false; - main_window->close (); + restart (RepositionType::replace); } else { @@ -682,14 +698,18 @@ void MultiSettings::impl::clone_into_configuration (QMainWindow * main_window, Q if (current_group.size ()) settings_.beginGroup (current_group); } -void MultiSettings::impl::reset_configuration (QMainWindow * main_window, QMenu const * menu) +void MultiSettings::impl::reset_configuration (QMenu const * menu) { + Q_ASSERT (main_window_); + if (!main_window_) return; + auto const& target_name = menu->title (); - if (MessageBox::Yes != MessageBox::query_message (main_window, - tr ("Reset Configuration"), - tr ("Confirm reset to default values for configuration \"%1\"?") - .arg (unescape_ampersands (target_name)))) + if (!main_window_ + || MessageBox::Yes != MessageBox::query_message (main_window_, + tr ("Reset Configuration"), + tr ("Confirm reset to default values for configuration \"%1\"?") + .arg (unescape_ampersands (target_name)))) { return; } @@ -697,10 +717,8 @@ void MultiSettings::impl::reset_configuration (QMainWindow * main_window, QMenu if (target_name == current_) { // restart with default settings - reposition_type_ = RepositionType::replace; new_settings_.clear (); - exit_flag_ = false; - main_window->close (); + restart (RepositionType::replace); } else { @@ -717,8 +735,11 @@ void MultiSettings::impl::reset_configuration (QMainWindow * main_window, QMenu } } -void MultiSettings::impl::rename_configuration (QMainWindow * main_window, QMenu * menu) +void MultiSettings::impl::rename_configuration (QMenu * menu) { + Q_ASSERT (main_window_); + if (!main_window_) return; + auto const& current_group = settings_.group (); if (current_group.size ()) settings_.endGroup (); auto const& target_name = menu->title (); @@ -729,7 +750,7 @@ void MultiSettings::impl::rename_configuration (QMainWindow * main_window, QMenu invalid_names << settings_.value (multi_settings_current_name_key).toString (); // get the new name - NameDialog dialog {target_name, invalid_names, main_window}; + NameDialog dialog {target_name, invalid_names, main_window_}; if (QDialog::Accepted == dialog.exec ()) { if (target_name == current_) @@ -760,8 +781,9 @@ void MultiSettings::impl::rename_configuration (QMainWindow * main_window, QMenu if (current_group.size ()) settings_.beginGroup (current_group); } -void MultiSettings::impl::delete_configuration (QMainWindow * main_window, QMenu * menu) +void MultiSettings::impl::delete_configuration (QMenu * menu) { + Q_ASSERT (main_window_); auto const& target_name = menu->title (); if (target_name == current_) @@ -770,10 +792,11 @@ void MultiSettings::impl::delete_configuration (QMainWindow * main_window, QMenu } else { - if (MessageBox::Yes != MessageBox::query_message (main_window, - tr ("Delete Configuration"), - tr ("Confirm deletion of configuration \"%1\"?") - .arg (unescape_ampersands (target_name)))) + if (!main_window_ + || MessageBox::Yes != MessageBox::query_message (main_window_, + tr ("Delete Configuration"), + tr ("Confirm deletion of configuration \"%1\"?") + .arg (unescape_ampersands (target_name)))) { return; } @@ -789,3 +812,12 @@ void MultiSettings::impl::delete_configuration (QMainWindow * main_window, QMenu // update the menu menu->deleteLater (); } + +void MultiSettings::impl::restart (RepositionType type) +{ + Q_ASSERT (main_window_); + reposition_type_ = type; + exit_flag_ = false; + main_window_->close (); + main_window_ = nullptr; +} diff --git a/MultiSettings.hpp b/MultiSettings.hpp index 051553b48..5e0c9a679 100644 --- a/MultiSettings.hpp +++ b/MultiSettings.hpp @@ -80,6 +80,10 @@ public: // action is triggered. void create_menu_actions (QMainWindow *, QMenu *); + // switch to this configuration if it exists + Q_SLOT void select_configuration (QString const& name); + QString configuration_name () const; + // Access to the QSettings object instance. QSettings * settings (); diff --git a/NEWS b/NEWS index 79ec823de..4d9f14e3d 100644 --- a/NEWS +++ b/NEWS @@ -13,9 +13,31 @@ Copyright 2001 - 2019 by Joe Taylor, K1JT. - Release: WSJT-X 2.0.1 - February 25, 2019 - --------------------- + Release: WSJT-X 2.1 + July 15, 2019 + ------------------- + +WSJT-X 2.1 is a major update that introduces FT4, a new protocol +targeted at HF contesting. Other improvements have been made in the +following areas: + + - FT8 waveform generated with GMSK, fully backward compatible + - user options for waterfall and spectrum display + - contest logging + - rig control + - user interface + - UDP messaging for inter-program communication + - accessibility + +There are numerous minor enhancements and bug fixes. + +We now provide a separate installation package for 64-bit Windows 7 +and later, with significant improvements in decoding speed. + + + Release: WSJT-X 2.0.1 + February 25, 2019 + --------------------- WSJT-X 2.0.1 is a bug fix release including the following defect repairs reported since the v2.0.0 GA release. @@ -67,9 +89,9 @@ repairs reported since the v2.0.0 GA release. than one Hound in the same Tx sequence. - Release: WSJT-X 2.0 - December 10, 2018 - ----------------------- + Release: WSJT-X 2.0 + December 10, 2018 + ----------------------- WSJT-X 2.0 is a major update that introduces new protocols for FT8 and MSK144. The new protocols become the world-wide standards on December @@ -125,9 +147,9 @@ Some details of changes since WSJT-X-rc5 include the following: - Update the WSJT-X User Guide to v2.0 (more to come...) - Update cty.dat - Release: WSJT-X 2.0-rc5 - November 26, 2018 - ----------------------- + Release: WSJT-X 2.0-rc5 + November 26, 2018 + ----------------------- Release Candidate 5 ("RC5") is stable, works well, and fixes the known problems in RC4. It is likely that the General Availability (GA) @@ -158,9 +180,9 @@ not be realized until most signals on a crowded band are using the new FT8 protocol. - Release: WSJT-X 2.0-rc4 - November 12, 2018 - ----------------------- + Release: WSJT-X 2.0-rc4 + November 12, 2018 + ----------------------- Changes from WSJT-X Version 2.0.0-rc3 include the following: @@ -184,9 +206,9 @@ Changes from WSJT-X Version 2.0.0-rc3 include the following: - New facilities for Contest and Fox-mode logging - Release: WSJT-X 2.0-rc3 - October 15, 2018 - ----------------------- + Release: WSJT-X 2.0-rc3 + October 15, 2018 + ----------------------- Changes from WSJT-X Version 2.0.0-rc2 include the following: @@ -210,9 +232,9 @@ Changes from WSJT-X Version 2.0.0-rc2 include the following: - Auto update of LoTW info, and faster program startup - Release: WSJT-X 2.0-rc2 - September 25, 2018 - ----------------------- + Release: WSJT-X 2.0-rc2 + September 25, 2018 + ----------------------- Changes from WSJT-X Version 2.0.0-rc1 include the following: - Corrected a flaw that encoded a message's first callsign as @@ -238,9 +260,9 @@ Changes from WSJT-X Version 2.0.0-rc1 include the following: - Suppressed the display of certain illogical false decodes. - Release: WSJT-X 2.0-rc1 - September 17, 2018 - ----------------------- + Release: WSJT-X 2.0-rc1 + September 17, 2018 + ----------------------- This is the first candidate release on WSJT-X 2.0, intended for beta-level testing. For details see: @@ -250,18 +272,18 @@ http://physics.princeton.edu/pulsar/k1jt/Quick_Start_WSJT-X_2.0.pdf http://physics.princeton.edu/pulsar/k1jt/77bit.txt - Release: WSJT-X Version 1.9.1 - June 1, 2018 - ----------------------------- + Release: WSJT-X Version 1.9.1 + June 1, 2018 + ----------------------------- This critical bug fix release repairs an unintended restriction in the FT8 DXpedition mode. It supersedes v1.9.0 and must be used for DXpedition Fox operators. - Release: WSJT-X Version 1.9.0 - May 28, 2018 - ----------------------------- + Release: WSJT-X Version 1.9.0 + May 28, 2018 + ----------------------------- Changes from WSJT-X Version 1.9.0-rc4 include the following: - Display in the right text window of MSK144 messages addressed to @@ -289,9 +311,9 @@ Changes from WSJT-X Version 1.9.0-rc4 include the following: - Hamlib, improved support for flrig. - Release: WSJT-X Version 1.9.0-rc4 - April 30, 2018 - --------------------------------- + Release: WSJT-X Version 1.9.0-rc4 + April 30, 2018 + --------------------------------- Changes from WSJT-X Version 1.9.0-rc3 include the following: @@ -321,9 +343,9 @@ Changes from WSJT-X Version 1.9.0-rc3 include the following: - Updated copy of cty.dat - Release: WSJT-X Version 1.9.0-rc3 - March 18, 2018 - --------------------------------- + Release: WSJT-X Version 1.9.0-rc3 + March 18, 2018 + --------------------------------- Changes from WSJT-X Version 1.9.0-rc2 include the following: @@ -357,9 +379,9 @@ Changes from WSJT-X Version 1.9.0-rc2 include the following: - Release: WSJT-X Version 1.9.0-rc2 - February 26, 2018 - --------------------------------- + Release: WSJT-X Version 1.9.0-rc2 + February 26, 2018 + --------------------------------- Changes from WSJT-X Version 1.8.0 include the following: @@ -401,9 +423,9 @@ wsjt-devel@lists.sourceforge.net. You must be a subscriber in order to post there. - Release: WSJT-X Version 1.8.0 - October 27, 2017 - ----------------------------- + Release: WSJT-X Version 1.8.0 + October 27, 2017 + ----------------------------- This is the full General Availability release of WSJT-X Version 1.8.0. @@ -424,9 +446,9 @@ reset of the default list of suggested operating frequencies. Go to *Reset*. - Release: WSJT-X Version 1.8.0-rc3 - October 16, 2017 - --------------------------------- + Release: WSJT-X Version 1.8.0-rc3 + October 16, 2017 + --------------------------------- Most (but not all) changes since Version 1.8.0-rc2 involve user control of the increasingly popular FT8 mode. The "RC3" release also @@ -528,9 +550,9 @@ message from populating the Tx message boxes. - Release: WSJT-X Version 1.8.0-rc2 - September 2, 2017 - --------------------------------- + Release: WSJT-X Version 1.8.0-rc2 + September 2, 2017 + --------------------------------- Implementation of FT8 and its auto-sequencing feature is now more capable and more polished. The decoder is faster and better: it now @@ -552,8 +574,8 @@ frequencies. Go to *File->Settings->Frequencies*, right click on the table and select *Reset*. - Release: WSJT-X Version 1.8.0 - ----------------------------- + Release: WSJT-X Version 1.8.0 + ----------------------------- NEW FEATURES IN WSJT-X Version 1.8.0 ------------------------------------ @@ -606,8 +628,8 @@ prescription of steps to reproduce the undesired behavior. You must be a subscriber to post to either of these lists. - Brief Description of the FT8 Protocol - ------------------------------------- + Brief Description of the FT8 Protocol + ------------------------------------- WSJT-X Version 1.8.0 includes a new mode called FT8, developed by K9AN and K1JT. The mode name "FT8" stands for "Franke and Taylor, 8-FSK @@ -641,8 +663,8 @@ activated in v1.8.0. We haven't yet finalized what the three extra bits in the message payload will be used for. Suggestions are welcome! - -- Joe, K1JT, for the WSJT Development Team - + -- Joe, K1JT, for the WSJT Development Team + WSJT-X v1.6.0 Release Notice ============================ @@ -923,7 +945,7 @@ defect is resolved in the next release (v1.5). - WSJT-X ChangeLog + WSJT-X ChangeLog ------------------------------------------------------------------ October 7, 2013: Version 1.2.1, r3590 diff --git a/NetworkMessage.hpp b/NetworkMessage.hpp index 4783bb369..4628c29b8 100644 --- a/NetworkMessage.hpp +++ b/NetworkMessage.hpp @@ -116,15 +116,18 @@ * Tx Enabled bool * Transmitting bool * Decoding bool - * Rx DF qint32 - * Tx DF qint32 + * Rx DF quint32 + * Tx DF quint32 * DE call utf8 * DE grid utf8 * DX grid utf8 * Tx Watchdog bool * Sub-mode utf8 * Fast mode bool - * Special operation mode quint8 + * Special Operation Mode quint8 + * Frequency Tolerance quint32 + * T/R Period quint32 + * Configuration Name utf8 * * WSJT-X sends this status message when various internal state * changes to allow the server to track the relevant state of each @@ -133,19 +136,22 @@ * * Application start up, * "Enable Tx" button status changes, - * Dial frequency changes, - * Changes to the "DX Call" field, - * Operating mode, sub-mode or fast mode changes, - * Transmit mode changed (in dual JT9+JT65 mode), - * Changes to the "Rpt" spinner, - * After an old decodes replay sequence (see Replay below), - * When switching between Tx and Rx mode, - * At the start and end of decoding, - * When the Rx DF changes, - * When the Tx DF changes, - * When settings are exited, - * When the DX call or grid changes, - * When the Tx watchdog is set or reset. + * dial frequency changes, + * changes to the "DX Call" field, + * operating mode, sub-mode or fast mode changes, + * transmit mode changed (in dual JT9+JT65 mode), + * changes to the "Rpt" spinner, + * after an old decodes replay sequence (see Replay below), + * when switching between Tx and Rx mode, + * at the start and end of decoding, + * when the Rx DF changes, + * when the Tx DF changes, + * when settings are exited, + * when the DX call or grid changes, + * when the Tx watchdog is set or reset, + * when the frequency tolerance is changed, + * when the T/R period is changed, + * when the configuration name changes. * * The Special operation mode is an enumeration that indicates the * setting selected in the WSJT-X "Settings->Advanced->Special @@ -159,6 +165,10 @@ * 5 -> FOX * 6 -> HOUND * + * The Frequency Tolerance and T/R period fields may have a value + * of the maximum quint32 value which implies the field is not + * applicable. + * * * Decode Out 2 quint32 * Id (unique key) utf8 @@ -271,11 +281,12 @@ * button. * * - * Close Out 6 quint32 + * Close Out/In 6 quint32 * Id (unique key) utf8 * - * Close is sent by a client immediately prior to it shutting - * down gracefully. + * Close is sent by a client immediately prior to it shutting + * down gracefully. When sent by a server it requests the target + * client to close down gracefully. * * * Replay In 7 quint32 @@ -414,6 +425,35 @@ * the last instance only instead of all instances of the * specified call be highlighted or have it's highlighting * cleared. + * + * + * SwitchConfiguration In 14 quint32 + * Id (unique key) utf8 + * Configuration Name utf8 + * + * The server may send this message at any time. The message + * specifies the name of the configuration to switch to. The new + * configuration must exist. + * + * + * Configure In 15 quint32 + * Id (unique key) utf8 + * Mode utf8 + * Frequency Tolerance quint32 + * Submode utf8 + * Fast Mode bool + * T/R Period quint32 + * Rx DF quint32 + * DX Call utf8 + * DX Grid utf8 + * Generate Messages bool + * + * The server may send this message at any time. The message + * specifies various configuration options. For utf8 string + * fields an empty value implies no change, for the quint32 Rx DF + * and Frequency Tolerance fields the maximum quint32 value + * implies no change. Invalid or unrecognized values will be + * silently ignored. */ #include @@ -443,6 +483,8 @@ namespace NetworkMessage Location, LoggedADIF, HighlightCallsign, + SwitchConfiguration, + Configure, maximum_message_type_ // ONLY add new message types // immediately before here }; diff --git a/OmniRigTransceiver.cpp b/OmniRigTransceiver.cpp index 09f1e5cfa..de352fb5a 100644 --- a/OmniRigTransceiver.cpp +++ b/OmniRigTransceiver.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "qt_helpers.hpP" @@ -109,6 +110,15 @@ OmniRigTransceiver::OmniRigTransceiver (std::unique_ptr wrapped { } +// returns false on time out +bool OmniRigTransceiver::await_notification_with_timeout (int timeout) +{ + QEventLoop el; + connect (this, &OmniRigTransceiver::notified, &el, [&el] () {el.exit (1);}); + QTimer::singleShot (timeout, Qt::CoarseTimer, &el, [&el] () {el.exit (0);}); + return 1 == el.exec (); // wait for notify or timer +} + int OmniRigTransceiver::do_start () { TRACE_CAT ("OmniRigTransceiver", "starting"); @@ -182,101 +192,109 @@ int OmniRigTransceiver::do_start () .arg (readable_params_, 8, 16, QChar ('0')) .arg (writable_params_, 8, 16, QChar ('0')) .arg (rig_number_).toLocal8Bit ()); - - offline_timer_.reset (new QTimer); - offline_timer_->setSingleShot (true); - offline_timer_->setInterval (5 * 1000); - connect (&*offline_timer_, &QTimer::timeout, this, &OmniRigTransceiver::timeout_check); - - for (unsigned tries {0}; tries < 10; ++tries) + for (int i = 0; i < 5; ++i) { - QThread::msleep (100); // wait until OmniRig polls the rig - auto f = rig_->GetRxFrequency (); - int resolution {0}; - if (f) + if (OmniRig::ST_ONLINE == rig_->Status ()) { - if (OmniRig::PM_UNKNOWN == rig_->Vfo () - && (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB)) - == (OmniRig::PM_VFOA | OmniRig::PM_VFOB)) - { - // start with VFO A (probably MAIN) on rigs that we - // can't query VFO but can set explicitly - rig_->SetVfo (OmniRig::PM_VFOA); - } - if (f % 10) return resolution; // 1Hz resolution - auto test_frequency = f - f % 100 + 55; - if (OmniRig::PM_FREQ & writable_params_) - { - rig_->SetFreq (test_frequency); - } - else if (reversed_ && (OmniRig::PM_FREQB & writable_params_)) - { - rig_->SetFreqB (test_frequency); - } - else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_)) - { - rig_->SetFreqA (test_frequency); - } - else - { - throw_qstring (tr ("OmniRig: don't know how to set rig frequency")); - } - switch (rig_->GetRxFrequency () - test_frequency) - { - case -5: resolution = -1; break; // 10Hz truncated - case 5: resolution = 1; break; // 10Hz rounded - case -15: resolution = -2; break; // 20Hz truncated - case -55: resolution = -2; break; // 100Hz truncated - case 45: resolution = 2; break; // 100Hz rounded - } - if (1 == resolution) // may be 20Hz rounded - { - test_frequency = f - f % 100 + 51; - if (OmniRig::PM_FREQ & writable_params_) - { - rig_->SetFreq (test_frequency); - } - else if (reversed_ && (OmniRig::PM_FREQB & writable_params_)) - { - rig_->SetFreqB (test_frequency); - } - else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_)) - { - rig_->SetFreqA (test_frequency); - } - if (9 == rig_->GetRxFrequency () - test_frequency) - { - resolution = 2; // 20Hz rounded - } - } - if (OmniRig::PM_FREQ & writable_params_) - { - rig_->SetFreq (f); - } - else if (reversed_ && (OmniRig::PM_FREQB & writable_params_)) - { - rig_->SetFreqB (f); - } - else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_)) - { - rig_->SetFreqA (f); - } - update_rx_frequency (f); - return resolution; + break; + } + await_notification_with_timeout (1000); + } + if (OmniRig::ST_ONLINE != rig_->Status ()) + { + throw_qstring ("OmniRig: " + rig_->StatusStr ()); + } + auto f = rig_->GetRxFrequency (); + for (int i = 0; (f == 0) && (i < 5); ++i) + { + await_notification_with_timeout (1000); + f = rig_->GetRxFrequency (); + } + update_rx_frequency (f); + int resolution {0}; + if (OmniRig::PM_UNKNOWN == rig_->Vfo () + && (writable_params_ & (OmniRig::PM_VFOA | OmniRig::PM_VFOB)) + == (OmniRig::PM_VFOA | OmniRig::PM_VFOB)) + { + // start with VFO A (probably MAIN) on rigs that we + // can't query VFO but can set explicitly + rig_->SetVfo (OmniRig::PM_VFOA); + } + f = state ().frequency (); + if (f % 10) return resolution; // 1Hz resolution + auto test_frequency = f - f % 100 + 55; + if (OmniRig::PM_FREQ & writable_params_) + { + rig_->SetFreq (test_frequency); + } + else if (reversed_ && (OmniRig::PM_FREQB & writable_params_)) + { + rig_->SetFreqB (test_frequency); + } + else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_)) + { + rig_->SetFreqA (test_frequency); + } + else + { + throw_qstring (tr ("OmniRig: don't know how to set rig frequency")); + } + if (!await_notification_with_timeout (1000)) + { + TRACE_CAT ("OmniRigTransceiver", "do_start 1: wait timed out"); + throw_qstring (tr ("OmniRig: timeout waiting for update from rig")); + } + switch (rig_->GetRxFrequency () - test_frequency) + { + case -5: resolution = -1; break; // 10Hz truncated + case 5: resolution = 1; break; // 10Hz rounded + case -15: resolution = -2; break; // 20Hz truncated + case -55: resolution = -2; break; // 100Hz truncated + case 45: resolution = 2; break; // 100Hz rounded + } + if (1 == resolution) // may be 20Hz rounded + { + test_frequency = f - f % 100 + 51; + if (OmniRig::PM_FREQ & writable_params_) + { + rig_->SetFreq (test_frequency); + } + else if (reversed_ && (OmniRig::PM_FREQB & writable_params_)) + { + rig_->SetFreqB (test_frequency); + } + else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_)) + { + rig_->SetFreqA (test_frequency); + } + if (!await_notification_with_timeout (2000)) + { + TRACE_CAT ("OmniRigTransceiver", "do_start 2: wait timed out"); + throw_qstring (tr ("OmniRig: timeout waiting for update from rig")); + } + if (9 == rig_->GetRxFrequency () - test_frequency) + { + resolution = 2; // 20Hz rounded } } - throw_qstring (tr ("OmniRig: Initialization timed out")); - return 0; // keep compiler happy + if (OmniRig::PM_FREQ & writable_params_) + { + rig_->SetFreq (f); + } + else if (reversed_ && (OmniRig::PM_FREQB & writable_params_)) + { + rig_->SetFreqB (f); + } + else if (!reversed_ && (OmniRig::PM_FREQA & writable_params_)) + { + rig_->SetFreqA (f); + } + update_rx_frequency (f); + return resolution; } void OmniRigTransceiver::do_stop () { - if (offline_timer_) - { - offline_timer_->stop (); - offline_timer_.reset (); - } - QThread::msleep (200); // leave some time for pending // commands at the server end if (port_) @@ -300,17 +318,6 @@ void OmniRigTransceiver::do_stop () TRACE_CAT ("OmniRigTransceiver", "stopped"); } -void OmniRigTransceiver::do_sync (bool force_signal, bool /*no_poll*/) -{ - // nothing much we can do here, we just have to let OmniRig do its - // stuff and its first poll should send us and update that will - // trigger a update signal from us. Any attempt to query OmniRig - // leads to a whole mess of trouble since its internal state is - // garbage until it has done its first rig poll. - send_update_signal_ = force_signal; - update_complete (); -} - void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString desc, QString help) { TRACE_CAT ("OmniRigTransceiver", QString::number (code) + " at " + source + ": " + desc + " (" + help + ')'); @@ -319,16 +326,20 @@ void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString void OmniRigTransceiver::handle_visible_change () { + if (!omni_rig_ || omni_rig_->isNull ()) return; TRACE_CAT ("OmniRigTransceiver", "visibility change: visibility =" << omni_rig_->DialogVisible ()); } void OmniRigTransceiver::handle_rig_type_change (int rig_number) { + if (!omni_rig_ || omni_rig_->isNull ()) return; + TRACE_CAT ("OmniRigTransceiver", "rig type change: rig =" << rig_number); if (rig_number_ == rig_number) { + if (!rig_ || rig_->isNull ()) return; readable_params_ = rig_->ReadableParams (); writable_params_ = rig_->WriteableParams (); - TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"} + TRACE_CAT ("OmniRigTransceiver", QString {"rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"} .arg (rig_->RigType ()) .arg (readable_params_, 8, 16, QChar ('0')) .arg (writable_params_, 8, 16, QChar ('0')) @@ -338,48 +349,47 @@ void OmniRigTransceiver::handle_rig_type_change (int rig_number) void OmniRigTransceiver::handle_status_change (int rig_number) { + if (!omni_rig_ || omni_rig_->isNull ()) return; + TRACE_CAT ("OmniRigTransceiver", QString {"status change for rig %1"}.arg (rig_number).toLocal8Bit ()); if (rig_number_ == rig_number) { + if (!rig_ || rig_->isNull ()) return; auto const& status = rig_->StatusStr ().toLocal8Bit (); - TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig status change: new status for rig %1 = "}.arg (rig_number).toLocal8Bit () << status); + TRACE_CAT ("OmniRigTransceiver", "OmniRig status change: new status = " << status); if (OmniRig::ST_ONLINE != rig_->Status ()) { - if (!offline_timer_->isActive ()) - { - offline_timer_->start (); // give OmniRig time to recover - } + offline ("Rig went offline"); } else { - offline_timer_->stop (); - update_rx_frequency (rig_->GetRxFrequency ()); - update_complete (); - TRACE_CAT ("OmniRigTransceiver", "OmniRig frequency:" << state ().frequency ()); + Q_EMIT notified (); } + // else + // { + // update_rx_frequency (rig_->GetRxFrequency ()); + // update_complete (); + // TRACE_CAT ("OmniRigTransceiver", "frequency:" << state ().frequency ()); + // } } } -void OmniRigTransceiver::timeout_check () -{ - offline ("Rig went offline"); -} - void OmniRigTransceiver::handle_params_change (int rig_number, int params) { - if (rig_number_ == rig_number) - { - TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig params change: params = 0x%1 for rig %2"} + if (!omni_rig_ || omni_rig_->isNull ()) return; + TRACE_CAT ("OmniRigTransceiver", QString {"params change: params = 0x%1 for rig %2"} .arg (params, 8, 16, QChar ('0')) .arg (rig_number).toLocal8Bit () << "state before:" << state ()); + if (rig_number_ == rig_number) + { + if (!rig_ || rig_->isNull ()) return; // starting_ = false; TransceiverState old_state {state ()}; auto need_frequency = false; - // state_.online = true; // sometimes we don't get an initial - // // OmniRig::ST_ONLINE status change - // // event + if (params & OmniRig::PM_VFOAA) { + TRACE_CAT ("OmniRigTransceiver", "VFOAA"); update_split (false); reversed_ = false; update_rx_frequency (rig_->FreqA ()); @@ -387,6 +397,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params) } if (params & OmniRig::PM_VFOAB) { + TRACE_CAT ("OmniRigTransceiver", "VFOAB"); update_split (true); reversed_ = false; update_rx_frequency (rig_->FreqA ()); @@ -394,6 +405,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params) } if (params & OmniRig::PM_VFOBA) { + TRACE_CAT ("OmniRigTransceiver", "VFOBA"); update_split (true); reversed_ = true; update_other_frequency (rig_->FreqA ()); @@ -401,6 +413,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params) } if (params & OmniRig::PM_VFOBB) { + TRACE_CAT ("OmniRigTransceiver", "VFOBB"); update_split (false); reversed_ = true; update_other_frequency (rig_->FreqA ()); @@ -408,154 +421,195 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params) } if (params & OmniRig::PM_VFOA) { + TRACE_CAT ("OmniRigTransceiver", "VFOA"); reversed_ = false; need_frequency = true; } if (params & OmniRig::PM_VFOB) { + TRACE_CAT ("OmniRigTransceiver", "VFOB"); reversed_ = true; need_frequency = true; } if (params & OmniRig::PM_FREQ) { + TRACE_CAT ("OmniRigTransceiver", "FREQ"); need_frequency = true; } if (params & OmniRig::PM_FREQA) { + auto f = rig_->FreqA (); + TRACE_CAT ("OmniRigTransceiver", "FREQA = " << f); if (reversed_) { - update_other_frequency (rig_->FreqA ()); + update_other_frequency (f); } else { - update_rx_frequency (rig_->FreqA ()); + update_rx_frequency (f); } } if (params & OmniRig::PM_FREQB) { + auto f = rig_->FreqB (); + TRACE_CAT ("OmniRigTransceiver", "FREQB = " << f); if (reversed_) { - update_rx_frequency (rig_->FreqB ()); + update_rx_frequency (f); } else { - update_other_frequency (rig_->FreqB ()); + update_other_frequency (f); } } if (need_frequency) { if (readable_params_ & OmniRig::PM_FREQA) { - if (reversed_) + auto f = rig_->FreqA (); + if (f) { - update_other_frequency (rig_->FreqA ()); + TRACE_CAT ("OmniRigTransceiver", "FREQA = " << f); + if (reversed_) + { + update_other_frequency (f); + } + else + { + update_rx_frequency (f); + } } - else - { - update_rx_frequency (rig_->FreqA ()); - } - need_frequency = false; } if (readable_params_ & OmniRig::PM_FREQB) { - if (reversed_) + auto f = rig_->FreqB (); + if (f) { - update_rx_frequency (rig_->FreqB ()); + TRACE_CAT ("OmniRigTransceiver", "FREQB = " << f); + if (reversed_) + { + update_rx_frequency (f); + } + else + { + update_other_frequency (f); + } + } + } + if (readable_params_ & OmniRig::PM_FREQ && !state ().ptt ()) + { + auto f = rig_->Freq (); + if (f) + { + TRACE_CAT ("OmniRigTransceiver", "FREQ = " << f); + update_rx_frequency (f); } - else - { - update_other_frequency (rig_->FreqB ()); - } - need_frequency = false; } - } - if (need_frequency && (readable_params_ & OmniRig::PM_FREQ) - && !state ().ptt ()) - { - update_rx_frequency (rig_->Freq ()); } if (params & OmniRig::PM_PITCH) { + TRACE_CAT ("OmniRigTransceiver", "PITCH"); } if (params & OmniRig::PM_RITOFFSET) { + TRACE_CAT ("OmniRigTransceiver", "RITOFFSET"); } if (params & OmniRig::PM_RIT0) { + TRACE_CAT ("OmniRigTransceiver", "RIT0"); } if (params & OmniRig::PM_VFOEQUAL) { auto f = readable_params_ & OmniRig::PM_FREQA ? rig_->FreqA () : rig_->Freq (); + auto m = map_mode (rig_->Mode ()); + TRACE_CAT ("OmniRigTransceiver", QString {"VFOEQUAL f=%1 m=%2"}.arg (f).arg (m)); update_rx_frequency (f); update_other_frequency (f); - update_mode (map_mode (rig_->Mode ())); + update_mode (m); } if (params & OmniRig::PM_VFOSWAP) { - auto temp = state ().tx_frequency (); + TRACE_CAT ("OmniRigTransceiver", "VFOSWAP"); + auto f = state ().tx_frequency (); update_other_frequency (state ().frequency ()); - update_rx_frequency (temp); + update_rx_frequency (f); update_mode (map_mode (rig_->Mode ())); } if (params & OmniRig::PM_SPLITON) { + TRACE_CAT ("OmniRigTransceiver", "SPLITON"); update_split (true); } if (params & OmniRig::PM_SPLITOFF) { + TRACE_CAT ("OmniRigTransceiver", "SPLITOFF"); update_split (false); } if (params & OmniRig::PM_RITON) { + TRACE_CAT ("OmniRigTransceiver", "RITON"); } if (params & OmniRig::PM_RITOFF) { + TRACE_CAT ("OmniRigTransceiver", "RITOFF"); } if (params & OmniRig::PM_XITON) { + TRACE_CAT ("OmniRigTransceiver", "XITON"); } if (params & OmniRig::PM_XITOFF) { + TRACE_CAT ("OmniRigTransceiver", "XITOFF"); } if (params & OmniRig::PM_RX) { + TRACE_CAT ("OmniRigTransceiver", "RX"); update_PTT (false); } if (params & OmniRig::PM_TX) { + TRACE_CAT ("OmniRigTransceiver", "TX"); update_PTT (); } if (params & OmniRig::PM_CW_U) { + TRACE_CAT ("OmniRigTransceiver", "CW-R"); update_mode (CW_R); } if (params & OmniRig::PM_CW_L) { + TRACE_CAT ("OmniRigTransceiver", "CW"); update_mode (CW); } if (params & OmniRig::PM_SSB_U) { + TRACE_CAT ("OmniRigTransceiver", "USB"); update_mode (USB); } if (params & OmniRig::PM_SSB_L) { + TRACE_CAT ("OmniRigTransceiver", "LSB"); update_mode (LSB); } if (params & OmniRig::PM_DIG_U) { + TRACE_CAT ("OmniRigTransceiver", "DATA-U"); update_mode (DIG_U); } if (params & OmniRig::PM_DIG_L) { + TRACE_CAT ("OmniRigTransceiver", "DATA-L"); update_mode (DIG_L); } if (params & OmniRig::PM_AM) { + TRACE_CAT ("OmniRigTransceiver", "AM"); update_mode (AM); } if (params & OmniRig::PM_FM) { + TRACE_CAT ("OmniRigTransceiver", "FM"); update_mode (FM); } @@ -566,6 +620,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params) } TRACE_CAT ("OmniRigTransceiver", "OmniRig params change: state after:" << state ()); } + Q_EMIT notified (); } void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& command, QVariant const& reply) @@ -573,8 +628,10 @@ void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& co (void)command; (void)reply; + if (!omni_rig_ || omni_rig_->isNull ()) return; if (rig_number_ == rig_number) { + if (!rig_ || rig_->isNull ()) return; TRACE_CAT ("OmniRigTransceiver", "custom command" << command.toString ().toLocal8Bit () << "with reply" << reply.toString ().toLocal8Bit () << QString ("for rig %1").arg (rig_number).toLocal8Bit ()); diff --git a/OmniRigTransceiver.hpp b/OmniRigTransceiver.hpp index c63266b69..2ba5fd4d3 100644 --- a/OmniRigTransceiver.hpp +++ b/OmniRigTransceiver.hpp @@ -38,10 +38,11 @@ public: void do_tx_frequency (Frequency, MODE, bool no_ignore) override; void do_mode (MODE) override; void do_ptt (bool on) override; - void do_sync (bool force_signal, bool no_poll) override; private: - Q_SLOT void timeout_check (); + bool await_notification_with_timeout (int timeout); + Q_SIGNAL void notified () const; + // Q_SLOT void timeout_check (); Q_SLOT void handle_COM_exception (int, QString, QString, QString); Q_SLOT void handle_visible_change (); Q_SLOT void handle_rig_type_change (int rig_number); @@ -62,7 +63,7 @@ private: QString rig_type_; int readable_params_; int writable_params_; - QScopedPointer offline_timer_; + // QScopedPointer offline_timer_; bool send_update_signal_; bool reversed_; // some rigs can reverse VFOs }; diff --git a/PollingTransceiver.cpp b/PollingTransceiver.cpp index b2bbab179..ed47144af 100644 --- a/PollingTransceiver.cpp +++ b/PollingTransceiver.cpp @@ -129,52 +129,46 @@ bool PollingTransceiver::do_pre_update () return true; } -void PollingTransceiver::do_sync (bool force_signal, bool no_poll) -{ - if (!no_poll) poll (); // tell sub-classes to update our state - - // Signal new state if it is directly requested or, what we expected - // or, hasn't become what we expected after polls_to_stabilize - // polls. Unsolicited changes will be signalled immediately unless - // they intervene in a expected sequence where they will be delayed. - if (retries_) - { - --retries_; - if (force_signal || state () == next_state_ || !retries_) - { - // our client wants a signal regardless - // or the expected state has arrived - // or there are no more retries - force_signal = true; - } - } - else if (force_signal || state () != last_signalled_state_) - { - // here is the normal passive polling path either our client has - // requested a state update regardless of change or state has - // changed asynchronously - force_signal = true; - } - - if (force_signal) - { - // reset everything, record and signal the current state - retries_ = 0; - next_state_ = state (); - last_signalled_state_ = state (); - update_complete (true); - } -} - void PollingTransceiver::handle_timeout () { QString message; + bool force_signal {false}; // we must catch all exceptions here since we are called by Qt and // inform our parent of the failure via the offline() message try { - do_sync (); + do_poll (); // tell sub-classes to update our state + + // Signal new state if it what we expected or, hasn't become + // what we expected after polls_to_stabilize polls. Unsolicited + // changes will be signalled immediately unless they intervene + // in a expected sequence where they will be delayed. + if (retries_) + { + --retries_; + if (state () == next_state_ || !retries_) + { + // the expected state has arrived or there are no more + // retries + force_signal = true; + } + } + else if (state () != last_signalled_state_) + { + // here is the normal passive polling path where state has + // changed asynchronously + force_signal = true; + } + + if (force_signal) + { + // reset everything, record and signal the current state + retries_ = 0; + next_state_ = state (); + last_signalled_state_ = state (); + update_complete (true); + } } catch (std::exception const& e) { diff --git a/PollingTransceiver.hpp b/PollingTransceiver.hpp index 0945c84ac..a9e639f9d 100644 --- a/PollingTransceiver.hpp +++ b/PollingTransceiver.hpp @@ -39,11 +39,9 @@ protected: QObject * parent); protected: - void do_sync (bool force_signal = false, bool no_poll = false) override final; - // Sub-classes implement this and fetch what they can from the rig // in a non-intrusive manner. - virtual void poll () = 0; + virtual void do_poll () = 0; void do_post_start () override final; void do_post_stop () override final; diff --git a/Radio.cpp b/Radio.cpp index 3940815f4..e5b34c35d 100644 --- a/Radio.cpp +++ b/Radio.cpp @@ -74,14 +74,14 @@ namespace Radio } - QString frequency_MHz_string (Frequency f, QLocale const& locale) + QString frequency_MHz_string (Frequency f, int precision, QLocale const& locale) { - return locale.toString (f / MHz_factor, 'f', frequency_precsion); + return locale.toString (f / MHz_factor, 'f', precision); } - QString frequency_MHz_string (FrequencyDelta d, QLocale const& locale) + QString frequency_MHz_string (FrequencyDelta d, int precision, QLocale const& locale) { - return locale.toString (d / MHz_factor, 'f', frequency_precsion); + return locale.toString (d / MHz_factor, 'f', precision); } QString pretty_frequency_MHz_string (Frequency f, QLocale const& locale) diff --git a/Radio.hpp b/Radio.hpp index 7f8b0a0f4..e63abf4b8 100644 --- a/Radio.hpp +++ b/Radio.hpp @@ -42,8 +42,8 @@ namespace Radio // // Frequency type formatting // - QString UDP_EXPORT frequency_MHz_string (Frequency, QLocale const& = QLocale ()); - QString UDP_EXPORT frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ()); + QString UDP_EXPORT frequency_MHz_string (Frequency, int precision = 6, QLocale const& = QLocale ()); + QString UDP_EXPORT frequency_MHz_string (FrequencyDelta, int precision = 6, QLocale const& = QLocale ()); QString UDP_EXPORT pretty_frequency_MHz_string (Frequency, QLocale const& = QLocale ()); QString UDP_EXPORT pretty_frequency_MHz_string (double, int scale, QLocale const& = QLocale ()); QString UDP_EXPORT pretty_frequency_MHz_string (FrequencyDelta, QLocale const& = QLocale ()); diff --git a/Release_Notes.txt b/Release_Notes.txt index c59ffafca..0484dd604 100644 --- a/Release_Notes.txt +++ b/Release_Notes.txt @@ -12,6 +12,178 @@ Copyright 2001 - 2019 by Joe Taylor, K1JT. + Release: WSJT-X 2.1 + July 15, 2019 + ------------------- + +WSJT-X 2.1 is a major update that introduces FT4, a new protocol +targeted at HF contesting. Other improvements have been made in the +following areas: + + - FT8 waveform generated with GMSK, fully backward compatible + - user options for waterfall and spectrum display + - contest logging + - rig control + - user interface + - UDP messaging for inter-program communication + - accessibility + +There are numerous minor enhancements and bug fixes. + +We now provide a separate installation package for 64-bit Windows 7 +and later, with significant improvements in decoding speed. + + Release: WSJT-X 2.1.0-rc7 + June 3, 2019 + ------------------------- + +This release is a bug fix only release addressing regressions in the +prior RC6 release. There are no functional changes other than an +updated AD1C CTY.DAT database. + + + Release: WSJT-X 2.1.0-rc6 + June 2, 2019 + ------------------------- + +Changes and bug fixes since WSJT-X 2.1.0-rc5: + +IMPORTANT CHANGES TO THE FT4 PROTOCOL *** NOT BACKWARD COMPATIBLE *** + - T/R sequence length increased from 6.0 to 7.5 seconds + - Symbol rate decreased from 23.4375 to 20.8333 baud + - Signal bandwidth decreased from 90 Hz to 80 Hz + +OTHER FT4 IMPROVEMENTS + - Allowable time offsets -1.0 < DT < +1.0 s + - Tx4 message with RRR now allowed, except in contest messages + - Audio frequency is now sent to PSK Reporter + - Add a third decoding pass + - Add ordered statistics decoding + - Improved sensitivity: threshold S/N is now -17.5 dB + - Improved S/N calculation + - In FT4 mode, Shift+F11/F12 moves Tx freq by +/- 100 Hz + +OTHER IMPROVEMENTS + - Improvements to accessibility + - Updates to the User Guide (not yet complete, however) + - New user option: "Calling CQ forces Call 1st" + - N1MM Logger+ now uses the standard WSJT-X UDP messages + - OK/Cancel buttons on Log QSO window maintain fixed positions + - Put EU VHF contest serial numbers into the ADIF SRX and STX fields + - Enhancements to the Omni-Rig CAT interface + - New setting option to include or exclude WAE entities + +BUG FIXES + - Fix generation of Tx5 message when one callsign is nonstandard + - Fix a bug that prevented use on macOS + - Fix a bug that caused mode switch from FT4 to FT8 + - Fix a bug that caused FT4 to do WSPR-style band hopping + - Fix a bug that caused a Fortran bounds error + - Repaired field editing in the Contest Log window + +Release candidate WSJT-X 2.1.0-rc6 will be available for beta-testing +through July 21, 2019. It will be inoperable during the ARRL June VHF +QSO Party (June 8-10) or ARRL Field Day (June 22-23). It will +permanently cease to function after July 21, 2019. If all goes +according to plan, by that time there will be a General +Availability (GA) release of WSJT-X 2.1.0. + + + Release: WSJT-X 2.1.0-rc5 + April 29, 2019 + ------------------------- + +WSJT-X 2.1.0 fifth release candidate is a minor release including the +following. + + - Repairs a defect that stopped messages from UDP servers being accepted. + - Improved message sequencing a QSO end for CQing FT4 stations. + - "Best S+P" action times out after two minutes waiting for a candidate. + - Updated macOS Info.plist to comply with latest mic. privacy controls. + - Multi-pass decoding for FT4 inc. prior decode subtraction. + - Fast/Normal/Deep options for the FT4 decoder. + - Proposed suggested working frequencies for the new FT4 mode. + - Repair a defect in RTTY RU where sequencer fails to advance to Tx3. + - Fix a defect where the contest serial # spin box was incorrectly hidden. + - Fix defects in ALL.TXT formatting for JT65 and JT9. + - Reduce timeout for AP decoding with own call from 10 mins to 5 mins. + + + Release: WSJT-X 2.1.0-rc4 + April 10, 2019 + ------------------------- + +WSJT-X 2.1.0 fourth release candidate is a minor release including the +following. + + - New "Call Best" button for FT4 mode to select the best reply to a + CQ call based on neediness. + - Fixed UTC display on FT4 waterfall. + +This release is made by invitation only to selected testers to trial +the FT4 mode in semi-realistic contest simulations and to elicit +feedback to guide future development. + +*Note* this release is not for general public release and we request + that it is not distributed. + + + Release: WSJT-X 2.1.0-rc3 + April 5, 2019 + ------------------------- + +WSJT-X 2.1.0 third release candidate is an enhancement release to +change the implementation of the new FT4 mode to a synchronous T/R +period of 6 seconds. + +This release is made by invitation only to selected testers to trial +the FT4 mode in semi-realistic contest simulations and to elicit +feedback to guide future development. + +*Note* this release is not for general public release and we request + that it is not distributed. + + + Release: WSJT-X 2.1.0-rc2 + March 29, 2019 + ------------------------- + +WSJT-X 2.1.0 second release candidate is a bug fix release to repair +some usability issues with FT4 contest mode. The following new +features are also included. + + - Better options for QSO flow by clicking Tx# buttons to transmit + - A 64-bit package for Windows 64-bit systems + - Improved FT4 sync detection speed + +This release is made by invitation only to selected testers to trial +the FT4 mode in semi-realistic contest simulations and to elicit +feedback to guide future development. + +*Note* this release is not for general public release and we request +that it is not distributed. + + Release: WSJT-X 2.1.0-rc1 + March 25, 2019 + ------------------------- + +WSJT-X 2.1.0 first release candidate is a preview alpha quality +release containing the following new features. + + - FT4 mode, a new mode targeted at HF digital contesting + - GMSK modulation for FT4 and FT8 + - New waterfall option to select between raw sensitivity or a + filtered signal representation for best visualization of signal + quality + +This release is made by invitation only to selected testers to trial +the FT4 mode in semi-realistic contest simulations and to elicit +feedback to guide future development. + +*Note* this release is not for general public release and we request +that it is not distributed. + + Release: WSJT-X 2.0.1 February 25, 2019 --------------------- diff --git a/TraceFile.cpp b/TraceFile.cpp index 2329b425f..87d4a82bb 100644 --- a/TraceFile.cpp +++ b/TraceFile.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include #include @@ -28,10 +30,11 @@ private: QTextStream * original_stream_; QtMessageHandler original_handler_; static QTextStream * current_stream_; + static QMutex mutex_; }; QTextStream * TraceFile::impl::current_stream_; - +QMutex TraceFile::impl::mutex_; // delegate to implementation class TraceFile::TraceFile (QString const& trace_file_path) @@ -73,7 +76,10 @@ TraceFile::impl::~impl () void TraceFile::impl::message_handler (QtMsgType type, QMessageLogContext const& context, QString const& msg) { Q_ASSERT_X (current_stream_, "TraceFile:message_handler", "no stream to write to"); - *current_stream_ << qFormatLogMessage (type, context, msg) << endl; + { + QMutexLocker lock {&mutex_}; // thread safety - serialize writes to the trace file + *current_stream_ << qFormatLogMessage (type, context, msg) << endl; + } if (QtFatalMsg == type) { diff --git a/TransceiverBase.cpp b/TransceiverBase.cpp index ef77d51e4..f1decb682 100644 --- a/TransceiverBase.cpp +++ b/TransceiverBase.cpp @@ -19,10 +19,10 @@ void TransceiverBase::start (unsigned sequence_number) noexcept QString message; try { + last_sequence_number_ = sequence_number; may_update u {this, true}; shutdown (); startup (); - last_sequence_number_ = sequence_number; } catch (std::exception const& e) { @@ -46,6 +46,7 @@ void TransceiverBase::set (TransceiverState const& s, QString message; try { + last_sequence_number_ = sequence_number; may_update u {this, true}; bool was_online {requested_.online ()}; if (!s.online () && was_online) @@ -115,7 +116,6 @@ void TransceiverBase::set (TransceiverState const& s, // record what actually changed requested_.ptt (actual_.ptt ()); } - last_sequence_number_ = sequence_number; } catch (std::exception const& e) { @@ -133,10 +133,27 @@ void TransceiverBase::set (TransceiverState const& s, void TransceiverBase::startup () { - Q_EMIT resolution (do_start ()); - do_post_start (); - actual_.online (true); - requested_.online (true); + QString message; + try + { + actual_.online (true); + requested_.online (true); + auto res = do_start (); + do_post_start (); + Q_EMIT resolution (res); + } + catch (std::exception const& e) + { + message = e.what (); + } + catch (...) + { + message = unexpected; + } + if (!message.isEmpty ()) + { + offline (message); + } } void TransceiverBase::shutdown () @@ -163,8 +180,8 @@ void TransceiverBase::shutdown () } do_stop (); do_post_stop (); - actual_.online (false); - requested_.online (false); + actual_ = TransceiverState {}; + requested_ = TransceiverState {}; } void TransceiverBase::stop () noexcept @@ -194,8 +211,11 @@ void TransceiverBase::stop () noexcept void TransceiverBase::update_rx_frequency (Frequency rx) { - actual_.frequency (rx); - requested_.frequency (rx); // track rig changes + if (rx) + { + actual_.frequency (rx); + requested_.frequency (rx); // track rig changes + } } void TransceiverBase::update_other_frequency (Frequency tx) diff --git a/TransceiverBase.hpp b/TransceiverBase.hpp index ea981d44b..7d43cc32e 100644 --- a/TransceiverBase.hpp +++ b/TransceiverBase.hpp @@ -112,8 +112,6 @@ protected: virtual void do_ptt (bool = true) = 0; virtual void do_post_ptt (bool = true) {} - virtual void do_sync (bool force_signal = false, bool no_poll = false) = 0; - virtual bool do_pre_update () {return true;} // sub classes report rig state changes with these methods diff --git a/UDPExamples/ClientWidget.cpp b/UDPExamples/ClientWidget.cpp index 1715670bf..ecf0b54fe 100644 --- a/UDPExamples/ClientWidget.cpp +++ b/UDPExamples/ClientWidget.cpp @@ -1,8 +1,11 @@ #include "ClientWidget.hpp" +#include #include #include +#include #include +#include #include "validators/MaidenheadLocatorValidator.hpp" @@ -11,6 +14,9 @@ namespace //QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"}; QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"}; QRegularExpression cq_re {"(CQ|CQDX|QRZ)[^A-Z0-9/]+"}; + QRegExpValidator message_validator {message_alphabet}; + MaidenheadLocatorValidator locator_validator; + quint32 quint32_max {std::numeric_limits::max ()}; void update_dynamic_property (QWidget * widget, char const * property, QVariant const& value) { @@ -21,9 +27,10 @@ namespace } } -ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id) - : client_id_ {client_id} - , rx_df_ (-1) +ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id, QObject * parent) + : QSortFilterProxyModel {parent} + , client_id_ {client_id} + , rx_df_ (quint32_max) { } @@ -49,7 +56,7 @@ QVariant ClientWidget::IdFilterModel::data (QModelIndex const& proxy_index, int break; case 4: // DF - if (qAbs (QSortFilterProxyModel::data (proxy_index).toInt () - rx_df_) <= 10) + if (qAbs (QSortFilterProxyModel::data (proxy_index).toUInt () - rx_df_) <= 10) { return QColor {255, 200, 200}; } @@ -87,7 +94,7 @@ void ClientWidget::IdFilterModel::de_call (QString const& call) } } -void ClientWidget::IdFilterModel::rx_df (int df) +void ClientWidget::IdFilterModel::rx_df (quint32 df) { if (df != rx_df_) { @@ -119,26 +126,48 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod , QListWidget const * calls_of_interest, QWidget * parent) : QDockWidget {make_title (id, version, revision), parent} , id_ {id} + , done_ {false} , calls_of_interest_ {calls_of_interest} - , decodes_proxy_model_ {id_} + , decodes_proxy_model_ {id} + , beacons_proxy_model_ {id} , erase_action_ {new QAction {tr ("&Erase Band Activity"), this}} , erase_rx_frequency_action_ {new QAction {tr ("Erase &Rx Frequency"), this}} , erase_both_action_ {new QAction {tr ("Erase &Both"), this}} - , decodes_table_view_ {new QTableView} - , beacons_table_view_ {new QTableView} - , message_line_edit_ {new QLineEdit} - , grid_line_edit_ {new QLineEdit} + , decodes_table_view_ {new QTableView {this}} + , beacons_table_view_ {new QTableView {this}} + , message_line_edit_ {new QLineEdit {this}} + , grid_line_edit_ {new QLineEdit {this}} + , generate_messages_push_button_ {new QPushButton {tr ("&Gen Msgs"), this}} + , auto_off_button_ {nullptr} + , halt_tx_button_ {nullptr} + , de_label_ {new QLabel {this}} + , frequency_label_ {new QLabel {this}} + , tx_df_label_ {new QLabel {this}} + , report_label_ {new QLabel {this}} + , configuration_line_edit_ {new QLineEdit {this}} + , mode_line_edit_ {new QLineEdit {this}} + , frequency_tolerance_spin_box_ {new QSpinBox {this}} + , tx_mode_label_ {new QLabel {this}} + , submode_line_edit_ {new QLineEdit {this}} + , fast_mode_check_box_ {new QCheckBox {this}} + , tr_period_spin_box_ {new QSpinBox {this}} + , rx_df_spin_box_ {new QSpinBox {this}} + , dx_call_line_edit_ {new QLineEdit {this}} + , dx_grid_line_edit_ {new QLineEdit {this}} + , decodes_page_ {new QWidget {this}} + , beacons_page_ {new QWidget {this}} + , content_widget_ {new QFrame {this}} + , status_bar_ {new QStatusBar {this}} + , control_button_box_ {new QDialogButtonBox {this}} + , form_layout_ {new QFormLayout} + , horizontal_layout_ {new QHBoxLayout} + , subform1_layout_ {new QFormLayout} + , subform2_layout_ {new QFormLayout} + , subform3_layout_ {new QFormLayout} + , decodes_layout_ {new QVBoxLayout {decodes_page_}} + , beacons_layout_ {new QVBoxLayout {beacons_page_}} + , content_layout_ {new QVBoxLayout {content_widget_}} , decodes_stack_ {new QStackedLayout} - , auto_off_button_ {new QPushButton {tr ("&Auto Off")}} - , halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}} - , de_label_ {new QLabel} - , mode_label_ {new QLabel} - , fast_mode_ {false} - , frequency_label_ {new QLabel} - , dx_label_ {new QLabel} - , rx_df_label_ {new QLabel} - , tx_df_label_ {new QLabel} - , report_label_ {new QLabel} , columns_resized_ {false} { // set up widgets @@ -152,11 +181,33 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod decodes_table_view_->insertAction (nullptr, erase_rx_frequency_action_); decodes_table_view_->insertAction (nullptr, erase_both_action_); - auto form_layout = new QFormLayout; - form_layout->addRow (tr ("Free text:"), message_line_edit_); - form_layout->addRow (tr ("Temporary grid:"), grid_line_edit_); - message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this}); - grid_line_edit_->setValidator (new MaidenheadLocatorValidator {this}); + message_line_edit_->setValidator (&message_validator); + grid_line_edit_->setValidator (&locator_validator); + dx_grid_line_edit_->setValidator (&locator_validator); + tr_period_spin_box_->setRange (5, 30); + tr_period_spin_box_->setSuffix (" s"); + rx_df_spin_box_->setRange (200, 5000); + frequency_tolerance_spin_box_->setRange (10, 1000); + frequency_tolerance_spin_box_->setPrefix ("\u00b1"); + frequency_tolerance_spin_box_->setSuffix (" Hz"); + + form_layout_->addRow (tr ("Free text:"), message_line_edit_); + form_layout_->addRow (tr ("Temporary grid:"), grid_line_edit_); + form_layout_->addRow (tr ("Configuration name:"), configuration_line_edit_); + form_layout_->addRow (horizontal_layout_); + subform1_layout_->addRow (tr ("Mode:"), mode_line_edit_); + subform2_layout_->addRow (tr ("Submode:"), submode_line_edit_); + subform3_layout_->addRow (tr ("Fast mode:"), fast_mode_check_box_); + subform1_layout_->addRow (tr ("T/R period:"), tr_period_spin_box_); + subform2_layout_->addRow (tr ("Rx DF:"), rx_df_spin_box_); + subform3_layout_->addRow (tr ("Freq. Tol:"), frequency_tolerance_spin_box_); + subform1_layout_->addRow (tr ("DX call:"), dx_call_line_edit_); + subform2_layout_->addRow (tr ("DX grid:"), dx_grid_line_edit_); + subform3_layout_->addRow (generate_messages_push_button_); + horizontal_layout_->addLayout (subform1_layout_); + horizontal_layout_->addLayout (subform2_layout_); + horizontal_layout_->addLayout (subform3_layout_); + connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) { Q_EMIT do_free_text (id_, text, false); }); @@ -166,66 +217,102 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod connect (grid_line_edit_, &QLineEdit::editingFinished, [this] () { Q_EMIT location (id_, grid_line_edit_->text ()); }); + connect (configuration_line_edit_, &QLineEdit::editingFinished, [this] () { + Q_EMIT switch_configuration (id_, configuration_line_edit_->text ()); + }); + connect (mode_line_edit_, &QLineEdit::editingFinished, [this] () { + QString empty; + Q_EMIT configure (id_, mode_line_edit_->text (), quint32_max, empty, fast_mode () + , quint32_max, quint32_max, empty, empty, false); + }); + connect (frequency_tolerance_spin_box_, static_cast (&QSpinBox::valueChanged), [this] (int i) { + QString empty; + auto f = frequency_tolerance_spin_box_->specialValueText ().size () ? quint32_max : i; + Q_EMIT configure (id_, empty, f, empty, fast_mode () + , quint32_max, quint32_max, empty, empty, false); + }); + connect (submode_line_edit_, &QLineEdit::editingFinished, [this] () { + QString empty; + Q_EMIT configure (id_, empty, quint32_max, submode_line_edit_->text (), fast_mode () + , quint32_max, quint32_max, empty, empty, false); + }); + connect (fast_mode_check_box_, &QCheckBox::stateChanged, [this] (int state) { + QString empty; + Q_EMIT configure (id_, empty, quint32_max, empty, Qt::Checked == state + , quint32_max, quint32_max, empty, empty, false); + }); + connect (tr_period_spin_box_, static_cast (&QSpinBox::valueChanged), [this] (int i) { + QString empty; + Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () + , i, quint32_max, empty, empty, false); + }); + connect (rx_df_spin_box_, static_cast (&QSpinBox::valueChanged), [this] (int i) { + QString empty; + Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () + , quint32_max, i, empty, empty, false); + }); + connect (dx_call_line_edit_, &QLineEdit::editingFinished, [this] () { + QString empty; + Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () + , quint32_max, quint32_max, dx_call_line_edit_->text (), empty, false); + }); + connect (dx_grid_line_edit_, &QLineEdit::editingFinished, [this] () { + QString empty; + Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () + , quint32_max, quint32_max, empty, dx_grid_line_edit_->text (), false); + }); - auto decodes_page = new QWidget; - auto decodes_layout = new QVBoxLayout {decodes_page}; - decodes_layout->setContentsMargins (QMargins {2, 2, 2, 2}); - decodes_layout->addWidget (decodes_table_view_); - decodes_layout->addLayout (form_layout); + decodes_layout_->setContentsMargins (QMargins {2, 2, 2, 2}); + decodes_layout_->addWidget (decodes_table_view_); + decodes_layout_->addLayout (form_layout_); - auto beacons_proxy_model = new IdFilterModel {id_}; - beacons_proxy_model->setSourceModel (beacons_model); - beacons_table_view_->setModel (beacons_proxy_model); + beacons_proxy_model_.setSourceModel (beacons_model); + beacons_table_view_->setModel (&beacons_proxy_model_); beacons_table_view_->verticalHeader ()->hide (); beacons_table_view_->hideColumn (0); beacons_table_view_->horizontalHeader ()->setStretchLastSection (true); beacons_table_view_->setContextMenuPolicy (Qt::ActionsContextMenu); beacons_table_view_->insertAction (nullptr, erase_action_); - auto beacons_page = new QWidget; - auto beacons_layout = new QVBoxLayout {beacons_page}; - beacons_layout->setContentsMargins (QMargins {2, 2, 2, 2}); - beacons_layout->addWidget (beacons_table_view_); + beacons_layout_->setContentsMargins (QMargins {2, 2, 2, 2}); + beacons_layout_->addWidget (beacons_table_view_); - decodes_stack_->addWidget (decodes_page); - decodes_stack_->addWidget (beacons_page); + decodes_stack_->addWidget (decodes_page_); + decodes_stack_->addWidget (beacons_page_); // stack alternative views - auto content_layout = new QVBoxLayout; - content_layout->setContentsMargins (QMargins {2, 2, 2, 2}); - content_layout->addLayout (decodes_stack_); + content_layout_->setContentsMargins (QMargins {2, 2, 2, 2}); + content_layout_->addLayout (decodes_stack_); // set up controls - auto control_button_box = new QDialogButtonBox; - control_button_box->addButton (auto_off_button_, QDialogButtonBox::ActionRole); - control_button_box->addButton (halt_tx_button_, QDialogButtonBox::ActionRole); + auto_off_button_ = control_button_box_->addButton (tr ("&Auto Off"), QDialogButtonBox::ActionRole); + halt_tx_button_ = control_button_box_->addButton (tr ("&Halt Tx"), QDialogButtonBox::ActionRole); + connect (generate_messages_push_button_, &QAbstractButton::clicked, [this] (bool /*checked*/) { + QString empty; + Q_EMIT configure (id_, empty, quint32_max, empty, fast_mode () + , quint32_max, quint32_max, empty, empty, true); + }); connect (auto_off_button_, &QAbstractButton::clicked, [this] (bool /* checked */) { Q_EMIT do_halt_tx (id_, true); }); connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) { Q_EMIT do_halt_tx (id_, false); }); - content_layout->addWidget (control_button_box); + content_layout_->addWidget (control_button_box_); // set up status area - auto status_bar = new QStatusBar; - status_bar->addPermanentWidget (de_label_); - status_bar->addPermanentWidget (mode_label_); - status_bar->addPermanentWidget (frequency_label_); - status_bar->addPermanentWidget (dx_label_); - status_bar->addPermanentWidget (rx_df_label_); - status_bar->addPermanentWidget (tx_df_label_); - status_bar->addPermanentWidget (report_label_); - content_layout->addWidget (status_bar); - connect (this, &ClientWidget::topLevelChanged, status_bar, &QStatusBar::setSizeGripEnabled); + status_bar_->addPermanentWidget (de_label_); + status_bar_->addPermanentWidget (tx_mode_label_); + status_bar_->addPermanentWidget (frequency_label_); + status_bar_->addPermanentWidget (tx_df_label_); + status_bar_->addPermanentWidget (report_label_); + content_layout_->addWidget (status_bar_); + connect (this, &ClientWidget::topLevelChanged, status_bar_, &QStatusBar::setSizeGripEnabled); // set up central widget - auto content_widget = new QFrame; - content_widget->setFrameStyle (QFrame::StyledPanel | QFrame::Sunken); - content_widget->setLayout (content_layout); - setWidget (content_widget); + content_widget_->setFrameStyle (QFrame::StyledPanel | QFrame::Sunken); + setWidget (content_widget_); // setMinimumSize (QSize {550, 0}); - setFeatures (DockWidgetMovable | DockWidgetFloatable); setAllowedAreas (Qt::BottomDockWidgetArea); setFloating (true); @@ -252,6 +339,25 @@ ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemMod } } +void ClientWidget::dispose () +{ + done_ = true; + close (); +} + +void ClientWidget::closeEvent (QCloseEvent *e) +{ + if (!done_) + { + Q_EMIT do_close (id_); + e->ignore (); // defer closure until client actually closes + } + else + { + QDockWidget::closeEvent (e); + } +} + ClientWidget::~ClientWidget () { for (int row = 0; row < calls_of_interest_->count (); ++row) @@ -261,16 +367,45 @@ ClientWidget::~ClientWidget () } } +bool ClientWidget::fast_mode () const +{ + return fast_mode_check_box_->isChecked (); +} + +namespace +{ + void update_line_edit (QLineEdit * le, QString const& value, bool allow_empty = true) + { + le->setEnabled (value.size () || allow_empty); + if (!(le->hasFocus () && le->isModified ())) + { + le->setText (value); + } + } + + void update_spin_box (QSpinBox * sb, int value, QString const& special_value = QString {}) + { + sb->setSpecialValueText (special_value); + bool enable {0 == special_value.size ()}; + sb->setEnabled (enable); + if (!sb->hasFocus () && enable) + { + sb->setValue (value); + } + } +} + void ClientWidget::update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call , QString const& report, QString const& tx_mode, bool tx_enabled - , bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df + , bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df , QString const& de_call, QString const& de_grid, QString const& dx_grid - , bool watchdog_timeout, QString const& sub_mode, bool fast_mode - , quint8 special_op_mode) + , bool watchdog_timeout, QString const& submode, bool fast_mode + , quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period + , QString const& configuration_name) { - if (id == id_) + if (id == id_) { - fast_mode_ = fast_mode; + fast_mode_check_box_->setChecked (fast_mode); decodes_proxy_model_.de_call (de_call); decodes_proxy_model_.rx_df (rx_df); QString special; @@ -288,21 +423,25 @@ void ClientWidget::update_status (QString const& id, Frequency f, QString const& .arg (de_grid.size () ? '(' + de_grid + ')' : QString {}) .arg (special) : QString {}); - mode_label_->setText (QString {"Mode: %1%2%3%4"} - .arg (mode) - .arg (sub_mode) - .arg (fast_mode && !mode.contains (QRegularExpression {R"(ISCAT|MSK144)"}) ? "fast" : "") + update_line_edit (mode_line_edit_, mode); + update_spin_box (frequency_tolerance_spin_box_, frequency_tolerance + , quint32_max == frequency_tolerance ? QString {"n/a"} : QString {}); + update_line_edit (submode_line_edit_, submode, false); + tx_mode_label_->setText (QString {"Tx Mode: %1"} .arg (tx_mode.isEmpty () || tx_mode == mode ? "" : '(' + tx_mode + ')')); frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f)); - dx_label_->setText (dx_call.size () >= 0 ? QString {"DX: %1%2"}.arg (dx_call) - .arg (dx_grid.size () ? '(' + dx_grid + ')' : QString {}) : QString {}); - rx_df_label_->setText (rx_df >= 0 ? QString {"Rx: %1"}.arg (rx_df) : ""); - tx_df_label_->setText (tx_df >= 0 ? QString {"Tx: %1"}.arg (tx_df) : ""); + update_line_edit (dx_call_line_edit_, dx_call); + update_line_edit (dx_grid_line_edit_, dx_grid); + if (rx_df != quint32_max) update_spin_box (rx_df_spin_box_, rx_df); + update_spin_box (tr_period_spin_box_, tr_period + , quint32_max == tr_period ? QString {"n/a"} : QString {}); + tx_df_label_->setText (QString {"Tx: %1"}.arg (tx_df)); report_label_->setText ("SNR: " + report); update_dynamic_property (frequency_label_, "transmitting", transmitting); auto_off_button_->setEnabled (tx_enabled); halt_tx_button_->setEnabled (transmitting); - update_dynamic_property (mode_label_, "decoding", decoding); + update_line_edit (configuration_line_edit_, configuration_name); + update_dynamic_property (mode_line_edit_, "decoding", decoding); update_dynamic_property (tx_df_label_, "watchdog_timeout", watchdog_timeout); } } diff --git a/UDPExamples/ClientWidget.hpp b/UDPExamples/ClientWidget.hpp index 22488531c..983ddd874 100644 --- a/UDPExamples/ClientWidget.hpp +++ b/UDPExamples/ClientWidget.hpp @@ -1,11 +1,11 @@ #ifndef WSJTX_UDP_CLIENT_WIDGET_MODEL_HPP__ #define WSJTX_UDP_CLIENT_WIDGET_MODEL_HPP__ +#include #include #include #include #include -#include #include "MessageServer.hpp" @@ -13,6 +13,20 @@ class QAbstractItemModel; class QModelIndex; class QColor; class QAction; +class QListWidget; +class QFormLayout; +class QVBoxLayout; +class QHBoxLayout; +class QStackedLayout; +class QTableView; +class QLineEdit; +class QAbstractButton; +class QLabel; +class QCheckBox; +class QSpinBox; +class QFrame; +class QStatusBar; +class QDialogButtonBox; using Frequency = MessageServer::Frequency; @@ -25,16 +39,18 @@ public: explicit ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model , QString const& id, QString const& version, QString const& revision , QListWidget const * calls_of_interest, QWidget * parent = nullptr); + void dispose (); ~ClientWidget (); - bool fast_mode () const {return fast_mode_;} + bool fast_mode () const; Q_SLOT void update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call , QString const& report, QString const& tx_mode, bool tx_enabled - , bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df + , bool transmitting, bool decoding, quint32 rx_df, quint32 tx_df , QString const& de_call, QString const& de_grid, QString const& dx_grid , bool watchdog_timeout, QString const& sub_mode, bool fast_mode - , quint8 special_op_mode); + , quint8 special_op_mode, quint32 frequency_tolerance, quint32 tr_period + , QString const& configuration_name); Q_SLOT void decode_added (bool is_new, QString const& client_id, QTime, qint32 snr , float delta_time, quint32 delta_frequency, QString const& mode , QString const& message, bool low_confidence, bool off_air); @@ -45,6 +61,7 @@ public: Q_SLOT void decodes_cleared (QString const& client_id); Q_SIGNAL void do_clear_decodes (QString const& id, quint8 window = 0); + Q_SIGNAL void do_close (QString const& id); Q_SIGNAL void do_reply (QModelIndex const&, quint8 modifier); Q_SIGNAL void do_halt_tx (QString const& id, bool auto_only); Q_SIGNAL void do_free_text (QString const& id, QString const& text, bool); @@ -52,30 +69,39 @@ public: Q_SIGNAL void highlight_callsign (QString const& id, QString const& call , QColor const& bg = QColor {}, QColor const& fg = QColor {} , bool last_only = false); + Q_SIGNAL void switch_configuration (QString const& id, QString const& configuration_name); + Q_SIGNAL void configure (QString const& id, QString const& mode, quint32 frequency_tolerance + , QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df + , QString const& dx_call, QString const& dx_grid, bool generate_messages); private: - QString id_; - QListWidget const * calls_of_interest_; class IdFilterModel final : public QSortFilterProxyModel { public: - IdFilterModel (QString const& client_id); + IdFilterModel (QString const& client_id, QObject * = nullptr); void de_call (QString const&); - void rx_df (int); + void rx_df (quint32); QVariant data (QModelIndex const& proxy_index, int role = Qt::DisplayRole) const override; - - protected: + private: bool filterAcceptsRow (int source_row, QModelIndex const& source_parent) const override; - private: QString client_id_; QString call_; QRegularExpression base_call_re_; - int rx_df_; - } decodes_proxy_model_; + quint32 rx_df_; + }; + + void closeEvent (QCloseEvent *) override; + + QString id_; + bool done_; + QListWidget const * calls_of_interest_; + IdFilterModel decodes_proxy_model_; + IdFilterModel beacons_proxy_model_; + QAction * erase_action_; QAction * erase_rx_frequency_action_; QAction * erase_both_action_; @@ -83,17 +109,39 @@ private: QTableView * beacons_table_view_; QLineEdit * message_line_edit_; QLineEdit * grid_line_edit_; - QStackedLayout * decodes_stack_; + QAbstractButton * generate_messages_push_button_; QAbstractButton * auto_off_button_; QAbstractButton * halt_tx_button_; QLabel * de_label_; - QLabel * mode_label_; - bool fast_mode_; QLabel * frequency_label_; - QLabel * dx_label_; - QLabel * rx_df_label_; QLabel * tx_df_label_; QLabel * report_label_; + QLineEdit * configuration_line_edit_; + QLineEdit * mode_line_edit_; + QSpinBox * frequency_tolerance_spin_box_; + QLabel * tx_mode_label_; + QLineEdit * submode_line_edit_; + QCheckBox * fast_mode_check_box_; + QSpinBox * tr_period_spin_box_; + QSpinBox * rx_df_spin_box_; + QLineEdit * dx_call_line_edit_; + QLineEdit * dx_grid_line_edit_; + QWidget * decodes_page_; + QWidget * beacons_page_; + QFrame * content_widget_; + QStatusBar * status_bar_; + QDialogButtonBox * control_button_box_; + + QFormLayout * form_layout_; + QHBoxLayout * horizontal_layout_; + QFormLayout * subform1_layout_; + QFormLayout * subform2_layout_; + QFormLayout * subform3_layout_; + QVBoxLayout * decodes_layout_; + QVBoxLayout * beacons_layout_; + QVBoxLayout * content_layout_; + QStackedLayout * decodes_stack_; + bool columns_resized_; }; diff --git a/UDPExamples/MessageAggregatorMainWindow.cpp b/UDPExamples/MessageAggregatorMainWindow.cpp index e6937e6cb..6245918a9 100644 --- a/UDPExamples/MessageAggregatorMainWindow.cpp +++ b/UDPExamples/MessageAggregatorMainWindow.cpp @@ -250,12 +250,15 @@ void MessageAggregatorMainWindow::add_client (QString const& id, QString const& connect (server_, &MessageServer::WSPR_decode, dock, &ClientWidget::beacon_spot_added); connect (server_, &MessageServer::decodes_cleared, dock, &ClientWidget::decodes_cleared); connect (dock, &ClientWidget::do_clear_decodes, server_, &MessageServer::clear_decodes); + connect (dock, &ClientWidget::do_close, server_, &MessageServer::close); connect (dock, &ClientWidget::do_reply, decodes_model_, &DecodesModel::do_reply); connect (dock, &ClientWidget::do_halt_tx, server_, &MessageServer::halt_tx); connect (dock, &ClientWidget::do_free_text, server_, &MessageServer::free_text); connect (dock, &ClientWidget::location, server_, &MessageServer::location); connect (view_action, &QAction::toggled, dock, &ClientWidget::setVisible); connect (dock, &ClientWidget::highlight_callsign, server_, &MessageServer::highlight_callsign); + connect (dock, &ClientWidget::switch_configuration, server_, &MessageServer::switch_configuration); + connect (dock, &ClientWidget::configure, server_, &MessageServer::configure); dock_widgets_[id] = dock; server_->replay (id); // request decodes and status } @@ -265,7 +268,7 @@ void MessageAggregatorMainWindow::remove_client (QString const& id) auto iter = dock_widgets_.find (id); if (iter != std::end (dock_widgets_)) { - (*iter)->close (); + (*iter)->dispose (); dock_widgets_.erase (iter); } } diff --git a/UDPExamples/UDPDaemon.cpp b/UDPExamples/UDPDaemon.cpp index 0ee202dc7..7caeb3038 100644 --- a/UDPExamples/UDPDaemon.cpp +++ b/UDPExamples/UDPDaemon.cpp @@ -51,7 +51,8 @@ public: , bool /*transmitting*/, bool /*decoding*/, qint32 /*rx_df*/, qint32 /*tx_df*/ , QString const& /*de_call*/, QString const& /*de_grid*/, QString const& /*dx_grid*/ , bool /* watchdog_timeout */, QString const& sub_mode, bool /*fast_mode*/ - , quint8 /*special_op_mode*/) + , quint8 /*special_op_mode*/, quint32 /*frequency_tolerance*/, quint32 /*tr_period*/ + , QString const& /*configuration_name*/) { if (id == id_) { diff --git a/Versions.cmake b/Versions.cmake index 450a98894..f9e94c26c 100644 --- a/Versions.cmake +++ b/Versions.cmake @@ -1,6 +1,6 @@ # Version number components set (WSJTX_VERSION_MAJOR 2) -set (WSJTX_VERSION_MINOR 0) -set (WSJTX_VERSION_PATCH 1) -set (WSJTX_RC 1) # release candidate number, comment out or zero for development versions +set (WSJTX_VERSION_MINOR 1) +set (WSJTX_VERSION_PATCH 0) +set (WSJTX_RC 8) # release candidate number, comment out or zero for development versions set (WSJTX_VERSION_IS_RELEASE 1) # set to 1 for final release build diff --git a/WSPRBandHopping.cpp b/WSPRBandHopping.cpp index fd0167d51..e954d5433 100644 --- a/WSPRBandHopping.cpp +++ b/WSPRBandHopping.cpp @@ -44,6 +44,8 @@ namespace class Dialog : public QDialog { + Q_OBJECT + public: using BandList = QList; @@ -69,6 +71,8 @@ private: static int constexpr band_index_role {Qt::UserRole}; }; +#include "WSPRBandHopping.moc" + Dialog::Dialog (QSettings * settings, Configuration const * configuration, BandList const * WSPR_bands , QBitArray * bands, int * gray_line_duration, QWidget * parent) : QDialog {parent, Qt::Window | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint} diff --git a/commons.h b/commons.h index 7c202d26e..4083bb22f 100644 --- a/commons.h +++ b/commons.h @@ -8,7 +8,8 @@ #ifdef __cplusplus #include extern "C" { -#else +#endif +#ifndef __cplusplus #include #endif diff --git a/cty.dat b/cty.dat index a94878c03..12882421d 100644 --- a/cty.dat +++ b/cty.dat @@ -48,7 +48,8 @@ ITU HQ: 14: 28: EU: 46.17: -6.05: -1.0: 4U1I: United Nations HQ: 05: 08: NA: 40.75: 73.97: 5.0: 4U1U: =4U1UN,=4U50SPACE,=4U60UN,=4U64UN,=4U70UN; Vienna Intl Ctr: 15: 28: EU: 48.20: -16.30: -1.0: *4U1V: - =4U0R,=4U10NPT,=4U18FIFA,=4U1A,=4U1VIC,=4U1WED,=4U1XMAS,=4U2U,=4U30VIC,=4U70VIC,=4Y1A,=C7A; + =4U0R,=4U10NPT,=4U18FIFA,=4U1A,=4U1VIC,=4U1WED,=4U1XMAS,=4U2U,=4U30VIC,=4U500M,=4U70VIC,=4Y1A, + =C7A; Timor - Leste: 28: 54: OC: -8.80: -126.05: -9.0: 4W: 4W,=4U1ET; Israel: 20: 39: AS: 31.32: -34.82: -2.0: 4X: @@ -118,15 +119,15 @@ West Malaysia: 28: 54: AS: 3.95: -102.23: -8.0: 9M2: =9W6MAN/2; East Malaysia: 28: 54: OC: 2.68: -113.32: -8.0: 9M6: 9M6,9M8,9W6,9W8,=9M1CSQ,=9M1CSS,=9M2/G3TMA/6,=9M2/PG5M/6,=9M2/R6AF/6,=9M2GCN/6,=9M2MDX/6, - =9M4ARD/6,=9M4CBP,=9M4CCB,=9M4CHQ,=9M4CJN,=9M4CMY,=9M4CPB,=9M4CRB,=9M4CSR,=9M4CWS,=9M4GCW,=9M4JSE, - =9M4LHM,=9M4LHS,=9M4LTW,=9M4RSA,=9M4SAB,=9M4SEB,=9M4SHQ,=9M4SJE,=9M4SJO,=9M4SJQ,=9M4SJS,=9M4SJSA, - =9M4SJSB,=9M4SJSD,=9M4SJSL,=9M4SJSP,=9M4SJST,=9M4SJSW,=9M4SJX,=9M4SMO,=9M4SMS,=9M4SMY,=9M4STA, - =9M4SWK,=9M50IARU/6,=9M50IARU/8,=9M50MQ,=9M50MS,=9M51GW,=9M51SB,=9M53QA,=9M57MS,=9M57MW,=9M58MS, - =9M58MW,=9M59MS,=9M59MW,=9M9/7M2VPR,=9M9/CCL,=9W2RCR/6,=9W2VVH/6; + =9M4ARD/6,=9M4CBP,=9M4CCB,=9M4CHQ,=9M4CJN,=9M4CKT,=9M4CMY,=9M4CPB,=9M4CRB,=9M4CRP,=9M4CSR,=9M4CWS, + =9M4GCW,=9M4JSE,=9M4LHM,=9M4LHS,=9M4LTW,=9M4RSA,=9M4SAB,=9M4SEB,=9M4SHQ,=9M4SJE,=9M4SJO,=9M4SJQ, + =9M4SJS,=9M4SJSA,=9M4SJSB,=9M4SJSD,=9M4SJSL,=9M4SJSP,=9M4SJST,=9M4SJSW,=9M4SJX,=9M4SMO,=9M4SMS, + =9M4SMY,=9M4STA,=9M4SWK,=9M50IARU/6,=9M50IARU/8,=9M50MQ,=9M50MS,=9M51GW,=9M51SB,=9M53QA,=9M57MS, + =9M57MW,=9M58MS,=9M58MW,=9M59MS,=9M59MW,=9M9/7M2VPR,=9M9/CCL,=9W2RCR/6,=9W2VVH/6; Nepal: 22: 42: AS: 27.70: -85.33: -5.75: 9N: 9N; Dem. Rep. of the Congo: 36: 52: AF: -3.12: -23.03: -1.0: 9Q: - 9O,9P,9Q,9R,9S,9T,=VERSION; + 9O,9P,9Q,9R,9S,9T; Burundi: 36: 52: AF: -3.17: -29.78: -2.0: 9U: 9U; Singapore: 28: 54: AS: 1.37: -103.78: -8.0: 9V: @@ -175,7 +176,7 @@ China: 24: 44: AS: 36.00: -102.00: -8.0: BY: BG,BG0(23)[42],BG9(23)[43],BH,BH0(23)[42],BH9(23)[43],BI,BI0(23)[42],BI9(23)[43],BJ,BJ0(23)[42], BJ9(23)[43],BL,BL0(23)[42],BL9(23)[43],BT,BT0(23)[42],BT9(23)[43],BY,BY0(23)[42],BY9(23)[43],BZ, BZ0(23)[42],BZ9(23)[43],XS,XS0(23)[42],XS9(23)[43],=B90IARU,=BD6KF/0(23)[42],=BD7MQ/9(23), - =BG6IFR/9(23),=BG9XD/4,=BG9XD/5,=BG9XD/7,=VO1AU/BY1RX,=VO1AU/BY1TTY,=W5FKX/BY1RX, + =BG6IFR/9(23),=BG9XD/4,=BG9XD/5,=BG9XD/7,=BH4CXY/9(23),=VO1AU/BY1RX,=VO1AU/BY1TTY,=W5FKX/BY1RX, =BA4DC/0(23)[42],=BD9BI/0(23)[42],=BG8FUL/0(23)[42], =BA4DT/0(23)[42],=BA4RF/0(23)[42],=BA7IO/0(23)[42],=BA7JS/0(23)[42],=BD1PTA/0(23)[42], =BD7IEE/0(23)[42],=BG1KIY/0(23)[42],=BG1LLB/0(23)[42],=BG1PIP/0(23)[42],=BG4WUA/0(23)[42], @@ -517,7 +518,7 @@ Antarctica: 13: 74: SA: -90.00: 0.00: 0.0: CE9: FT7Y(30)[70],FT8Y(30)[70], =VP8DLM[73], =FT5YK/KC4[73],=KC4/FT5YK[73], - =VP8/UT1KY[73], + =VP8/UT1KY[73],=VP8CTR[73], =VP8DJB/P[73], =VP8/G0VZM/P[73],=VP8/MM0TJR/P[73],=VP8BF[73],=VP8DJB[73],=VP8DOU[73],=VP8DPE[73],=VP8ROT[73], =VP8ADE[73],=VP8ADE/B[73],=VP8DLJ[73],=VP8DPJ[73], @@ -566,7 +567,7 @@ Antarctica: 13: 74: SA: -90.00: 0.00: 0.0: CE9: =LU/FT5YJ[73], =OR4TN(38)[67], =CE9/K2ARB(12), - =DH1HB/P(38)[67],=DH5CW(38)[67],=DP0/OJ1ABOA(38)[67],=DP0GVN(38)[67],=DP1POL(38)[67], + =DH1HB/P(38)[67],=DP0/OJ1ABOA(38)[67],=DP0GVN(38)[67],=DP1POL(38)[67], =FT5YJ/P[73], =R1ANR(38)[67],=RI1ANR(38)[67], =OH2FFP/P(38)[67], @@ -577,7 +578,9 @@ Antarctica: 13: 74: SA: -90.00: 0.00: 0.0: CE9: =D8A(30)[71], =DP1POL/P(38)[67], =KC4/K6REF(32)[71], - =DP0GVN/P(38)[67]; + =DP0GVN/P(38)[67], + =FT5YK/P[73], + =RI1ANX(38)[67]; Cuba: 08: 11: NA: 21.50: 80.00: 5.0: CM: CL,CM,CO,T4, =T40C/LT, @@ -598,7 +601,7 @@ Portugal: 14: 37: EU: 39.50: 8.00: 0.0: CT: Madeira Islands: 33: 36: AF: 32.75: 16.95: 0.0: CT3: CQ2,CQ3,CQ9,CR3,CR9,CS3,CS9,CT3,CT9,=CT9500AEP/J; Azores: 14: 36: EU: 38.70: 27.23: 1.0: CU: - CQ1,CQ8,CR1,CR2,CR8,CS4,CS8,CT8,CU, + CQ1,CQ8,CR1,CR2,CR8,CS4,CS8,CT8,CU,=CU2JU/ND, =CQ8ARN/LH, =CU5/CU3EJ/LH, =CT8/DK6EA/LH; @@ -629,15 +632,15 @@ Fed. Rep. of Germany: 14: 28: EU: 51.00: -10.00: -1.0: DL: =DF5FO/LH,=DF8AN/LGT,=DF8AN/LH,=DF8AN/P/LH,=DF9HG/LH,=DG0GF/LH,=DG3XA/LH,=DH0IPA/LH,=DH1DH/LH, =DH1DH/M/LH,=DH6RS/LH,=DH7RK/LH,=DH9JK/LH,=DH9UW/YL,=DJ0PJ/LH,=DJ2OC/LH,=DJ3XG/LH,=DJ5AA/LH, =DJ7AO/LH,=DJ7MH/LH,=DJ8RH/LH,=DJ9QE/LH,=DK0DAN/LH,=DK0FC/LGT,=DK0FC/LH,=DK0IZ/LH,=DK0KTL/LH, - =DK0LWL/L,=DK0LWL/LH,=DK0OC/LH,=DK0PRE/LH,=DK0RA/LH,=DK0RBY/LH,=DK0RU/LH,=DK0RZ/LH,=DK3DUA/LH, - =DK3R/LH,=DK4DS/LH,=DK4MT/LT,=DK5AN/P/LH,=DK5T/LH,=DK5T/LS,=DL/HB9DQJ/LH,=DL0AWG/LH,=DL0BLA/LH, - =DL0BPS/LH,=DL0BUX/LGT,=DL0BUX/LH,=DL0CA/LH,=DL0CUX/LGT,=DL0CUX/LV,=DL0DAB/LH,=DL0EJ/LH, - =DL0EM/LGT,=DL0EM/LH,=DL0EO/LGT,=DL0EO/LH,=DL0FFF/LGT,=DL0FFF/LH,=DL0FFF/LS,=DL0FHD/LH,=DL0FL/FF, - =DL0HDF/LH,=DL0HGW/LGT,=DL0HGW/LH,=DL0HST/LH,=DL0II/LH,=DL0IOO/LH,=DL0IPA/LH,=DL0LGT/LH, - =DL0LNW/LH,=DL0MCM/LH,=DL0MFH/LGT,=DL0MFH/LH,=DL0MFK/LGT,=DL0MFK/LH,=DL0MFN/LH,=DL0MHR/LH, - =DL0NH/LH,=DL0PAS/LH,=DL0PBS/LH,=DL0PJ/LH,=DL0RSH/LH,=DL0RUG/LGT,=DL0RUG/LH,=DL0RWE/LH,=DL0SH/LH, - =DL0SY/LH,=DL0TO/LH,=DL0UEM/LH,=DL0YLM/LH,=DL1BSN/LH,=DL1DUT/LH,=DL1ELU/LH,=DL1HZM/YL,=DL1SKK/LH, - =DL2FCA/YL,=DL2RPS/LH,=DL3ANK/LH,=DL3KWR/YL,=DL3KZA/LH,=DL3RNZ/LH,=DL4ABB/LH,=DL5CX/LH,=DL5KUA/LH, + =DK0LWL/LH,=DK0OC/LH,=DK0PRE/LH,=DK0RA/LH,=DK0RBY/LH,=DK0RU/LH,=DK0RZ/LH,=DK3DUA/LH,=DK3R/LH, + =DK4DS/LH,=DK4MT/LT,=DK5AN/P/LH,=DK5T/LH,=DK5T/LS,=DL/HB9DQJ/LH,=DL0AWG/LH,=DL0BLA/LH,=DL0BPS/LH, + =DL0BUX/LGT,=DL0BUX/LH,=DL0CA/LH,=DL0CUX/LGT,=DL0CUX/LV,=DL0DAB/LH,=DL0EJ/LH,=DL0EM/LGT,=DL0EM/LH, + =DL0EO/LGT,=DL0EO/LH,=DL0FFF/LGT,=DL0FFF/LH,=DL0FFF/LS,=DL0FHD/LH,=DL0FL/FF,=DL0HDF/LH, + =DL0HGW/LGT,=DL0HGW/LH,=DL0HST/LH,=DL0II/LH,=DL0IOO/LH,=DL0IPA/LH,=DL0LGT/LH,=DL0LNW/LH, + =DL0MCM/LH,=DL0MFH/LGT,=DL0MFH/LH,=DL0MFK/LGT,=DL0MFK/LH,=DL0MFN/LH,=DL0MHR/LH,=DL0NH/LH, + =DL0PAS/LH,=DL0PBS/LH,=DL0PJ/LH,=DL0RSH/LH,=DL0RUG/LGT,=DL0RUG/LH,=DL0RWE/LH,=DL0SH/LH,=DL0SY/LH, + =DL0TO/LH,=DL0UEM/LH,=DL0YLM/LH,=DL1BSN/LH,=DL1DUT/LH,=DL1ELU/LH,=DL1HZM/YL,=DL1SKK/LH,=DL2FCA/YL, + =DL2RPS/LH,=DL3ANK/LH,=DL3JJ/LH,=DL3KWR/YL,=DL3KZA/LH,=DL3RNZ/LH,=DL4ABB/LH,=DL5CX/LH,=DL5KUA/LH, =DL5SE/LH,=DL65DARC/LH,=DL6ABN/LH,=DL6AP/LH,=DL6KWN/LH,=DL7ANC/LH,=DL7BMG/LH,=DL7MFK/LH, =DL7UVO/LH,=DL7VDX/LH,=DL8HK/YL,=DL8MTG/LH,=DL8TG/LV,=DL8UAA/FF,=DL9CU/LH,=DL9NEI/ND2N,=DL9OE/LH, =DL9SEP/P/LH,=DM2C/LH,=DM3B/LH,=DM3G/LH,=DM3KF/LH,=DM5C/LH,=DM5JBN/LH,=DN0AWG/LH,=DN4MB/LH, @@ -666,47 +669,51 @@ Spain: 14: 37: EU: 40.37: 4.88: -1.0: EA: AM,AN,AO,EA,EB,EC,ED,EE,EF,EG,EH,=AN92EXPO,=EF6,=EG90IARU, =AM1TDH/LH,=EA1APV/LH,=EA1BEY/Y,=EA1EEY/L,=EA1EEY/LGT,=EA1EEY/LH,=EA1EK/ZAP,=EA1FGS/LH,=EA1HLW/YL, =EA1RCG/CPV,=EA1RCG/SEU,=EA1RCG/YOA,=EA1RCI/CA,=EA1RCI/CR,=EA1RCI/CVG,=EA1RCI/ESM,=EA1RCI/IA, - =EA1RCI/ICA,=EA1RCI/JBN,=EA1RCI/PAZ,=EA1RCI/PCV,=EA1RCI/RSM,=EA1RCI/YOA,=EA1URL/CVL,=EA1URO/D, - =EA5AER/P,=EA6QB/1,=EA8BFH/1,=EA8CZT/1,=EA8FC/1,=EA8RV/P,=EA9CD/1,=EA9CI/1,=EA9CP/1,=EA9PD/1, - =EB1DH/LH,=ED1IRM/LH,=EG1ILW/LH,=EG1LWC/LH,=EG1LWI/LH,=EG1LWN/LH,=EG1TDH/LH,=EG90IARU/1, + =EA1RCI/ICA,=EA1RCI/JBN,=EA1RCI/KD,=EA1RCI/PAZ,=EA1RCI/PCV,=EA1RCI/RSM,=EA1RCI/YOA,=EA1URL/CVL, + =EA1URO/D,=EA1URO/KD,=EA5AER/P,=EA6QB/1,=EA8BFH/1,=EA8CZT/1,=EA8FC/1,=EA8RV/P,=EA9CD/1,=EA9CI/1, + =EA9CP/1,=EA9PD/1,=EB1DH/LH,=ED1IRM/LH,=EG1ILW/LH,=EG1LWC/LH,=EG1LWI/LH,=EG1LWN/LH,=EG1TDH/LH, + =EG90IARU/1, =AM08ATU/H,=AM08CAZ/H,=AM08CYQ/H,=AM08EIE/Z,=AM08FAC/H,=AN08ADE/H,=AO08BQH/Z,=AO08BTM/Z, =AO08CIK/H,=AO08CVV/Z,=AO08CXK/H,=AO08CYL/H,=AO08DI/Z,=AO08EIE/Z,=AO08HV/Z,=AO08ICA/Z,=AO08ID/Z, =AO08KJ/Z,=AO08KV/Z,=AO08OK/H,=AO08PB/Z,=AO08RKO/H,=AO08VK/Z,=AO2016DSS/LH,=EA2/ON7RU/LH, - =EA2CRX/LH,=EA2EZ/P,=EA2SPS/LH,=EA2URI/O,=EA6SK/2,=EA9CP/2,=EG90IARU/2, - =EA3ESZ/Z,=EA3EVR/R,=EA3HSD/P,=EA3LD/D,=EA3RCV/PAZ,=EA8TL/3,=EA9CI/3,=EA9CP/3,=EG90IARU/3, + =EA2CRX/LH,=EA2SPS/LH,=EA2URI/O,=EA6SK/2,=EA9CP/2,=EG90IARU/2, + =EA2EZ/P,=EA3ESZ/Z,=EA3EVR/R,=EA3HSD/P,=EA3LD/D,=EA3RCV/PAZ,=EA6LU/3,=EA8TL/3,=EA9CI/3,=EA9CP/3, + =EG90IARU/3, =EA4AAQ/O,=EA4RCH/CIE,=EA6AFU/4,=EA6RC/4,=EA8BFH/4,=EA8BY/4,=EA9CI/4,=EA9CP/4,=EG8AOP/4, =EG90IARU/4, - =EA5ADM/P,=EA5CC/P,=EA5EQ/N,=EA5EZ/P,=EA5FL/LH,=EA5GVT/AVW,=EA5HCC/P,=EA5IKT/P,=EA5KB/LH,=EA5ND/D, - =EA5RCK/CDI,=EA5RKD/PAZ,=EA5TOM/AVW,=EA5URE/IVA,=EA5URE/P,=EA5URM/C,=EA5URM/F,=EA5URM/G,=EA5URM/H, - =EA5URM/I,=EA5URM/L,=EA5URR/PAZ,=EA5URV/CAC,=EA6AKN/5,=EA8BFH/5,=EA8CWF/5,=EA9BLJ/5,=EA9CI/5, - =EA9CP/5,=EA9PD/5,=ED5MFP/C,=ED5MFP/G,=ED5MFP/H,=ED5MFP/I,=ED5MFP/K,=ED5MFP/Q,=ED5MFP/R,=ED5MFP/S, - =ED5URD/LH,=EG90IARU/5,=EH5FL/LH, + =EA5/ON4LO/LH,=EA5ADM/P,=EA5CC/P,=EA5EQ/N,=EA5EZ/P,=EA5FL/LH,=EA5GVT/AVW,=EA5HCC/P,=EA5IKT/P, + =EA5KB/LH,=EA5ND/D,=EA5RCK/CDI,=EA5RKD/PAZ,=EA5TOM/AVW,=EA5URE/IVA,=EA5URE/P,=EA5URM/C,=EA5URM/F, + =EA5URM/G,=EA5URM/H,=EA5URM/I,=EA5URM/L,=EA5URR/PAZ,=EA5URV/CAC,=EA6AKN/5,=EA8BFH/5,=EA8CWF/5, + =EA9BLJ/5,=EA9CI/5,=EA9CP/5,=EA9PD/5,=ED5MFP/C,=ED5MFP/G,=ED5MFP/H,=ED5MFP/I,=ED5MFP/K,=ED5MFP/Q, + =ED5MFP/R,=ED5MFP/S,=ED5URD/LH,=EG90IARU/5,=EH5FL/LH, =AO7WRD/MA,=EA6SK/7,=EA7CFU/U,=EA7FC/FCJ,=EA7HZ/F,=EA7OBH/LH,=EA7URA/GET,=EA7URA/PAZ,=EA7URA/SG, =EA7URA/YOTA,=EA7URE/PAZ,=EA7URF/PAZ,=EA7URI/MDL,=EA7URJ/CPM,=EA7URL/FSV,=EA7URM/PAZ,=EA7URP/LAI, =EA9CP/7,=EA9FN/7,=EA9HU,=EA9HU/7,=EA9JS/7,=EA9LZ/7,=EA9PD/7,=EA9QD/7,=EA9UL/7,=EA9UV/7,=EB9PH/7, =EC7DZZ/LH,=EG90IARU/7; Balearic Islands: 14: 37: EU: 39.60: -2.95: -1.0: EA6: - AM6,AN6,AO6,EA6,EB6,EC6,ED6,EE6,EF6,EG6,EH6,=EA1QE/6,=EA1YO/6,=EA2EZ/6,=EA2SG/6,=EA2TW/6,=EA3BT/6, - =EA3CBH/6,=EA3ERT/6,=EA3HSD/6,=EA3HUX/6,=EA3HZX/6,=EA3HZX/P,=EA4LO/6,=EA5ADM/6,=EA5BB/6,=EA5BK/6, - =EA5BTL/6,=EA5EOR/6,=EA5ER/6,=EA5EZ/6,=EA5FL/P,=EA5HCC/6,=EA5IIG/6,=EA5IKT/6,=EA5RKB/6, - =EA6/DJ7AO/LH,=EA6/G0SGB/LH,=EA6HP/J,=EA6URI/PAZ,=EA6URL/IF,=EA7DUT/6,=EA9CI/6,=EA9CP/6,=EB1BRH/6, - =EB2GKK/6,=EB3CW/6,=EC5AC/6,=EC5BME/6,=EC5EA/P,=EC5EC/6,=EC6TV/N,=EC7AT/6,=ED4SHF/6,=ED5ON/6, - =EH90IARU/6; + AM6,AN6,AO6,EA6,EB6,EC6,ED6,EE6,EF6,EG6,EH6,=AM70URE/6,=EA1QE/6,=EA1YO/6,=EA2EZ/6,=EA2SG/6, + =EA2TW/6,=EA3BT/6,=EA3CBH/6,=EA3ERT/6,=EA3HSD/6,=EA3HUX/6,=EA3HZX/6,=EA3HZX/P,=EA4LO/6,=EA5ADM/6, + =EA5BB/6,=EA5BK/6,=EA5BTL/6,=EA5EOR/6,=EA5ER/6,=EA5EZ/6,=EA5FL/P,=EA5HCC/6,=EA5IIG/6,=EA5IKT/6, + =EA5RKB/6,=EA6/DJ7AO/LH,=EA6/G0SGB/LH,=EA6HP/J,=EA6LU/P,=EA6URI/PAZ,=EA6URL/IF,=EA7DUT/6,=EA9CI/6, + =EA9CP/6,=EB1BRH/6,=EB2GKK/6,=EB3CW/6,=EC5AC/6,=EC5BME/6,=EC5EA/P,=EC5EC/6,=EC6TV/N,=EC7AT/6, + =ED4SHF/6,=ED5ON/6,=EH90IARU/6; Canary Islands: 33: 36: AF: 28.32: 15.85: 0.0: EA8: - AM8,AN8,AO8,EA8,EB8,EC8,ED8,EE8,EF8,EG8,EH8,=AN400L,=AN400U,=AO150ITU/8,=AO150U,=AO4AAA/8, - =EA1AK/8,=EA1AP/8,=EA1EHW/8,=EA1YO/8,=EA3RKB/8,=EA4BQ/8,=EA4ESI/8,=EA4SV/8,=EA4WT/8,=EA4ZK/8, - =EA5BK/8,=EA5HCC/8,=EA5RKL/8,=EA7JR/8,=EA8/DJ5AA/LH,=EA8AKG/F,=EA8AKG/G,=EA8DO/LP,=EA8EE/L, - =EA8TH/LP,=EA8URE/YOTA,=EA8URL/LH,=EA8URL/P/SBI,=EA9CI/8,=EA9CP/8,=EB2EMH/8,=EC1KR/8,=EC8AFM/LH, - =ED4R/8,=ED5RKL/8,=ED8BTM/C,=ED8BTM/E,=ED8BTM/J,=ED8BTM/L,=ED8BTM/S,=ED8GSA/J,=ED8LIB/C,=ED8LIB/D, - =ED8LIB/E,=ED8LIB/F,=ED8LIB/G,=ED8LIB/H,=ED8LIB/I,=ED8LIB/J,=ED8LIB/K,=ED8LIB/N,=ED8LIB/O, - =ED8LIB/Q,=ED8LPA/L,=ED8MCC/LH,=ED8OTA/D,=ED8OTA/H,=ED8PDC/E,=ED8PDC/K,=ED8PDC/LP,=ED8PDC/O, - =EF8LIB/N,=EG8LIB/C,=EG8LIB/D,=EG8LIB/E,=EG8LIB/F,=EG8LIB/G,=EG8LIB/H,=EG8LIB/I,=EG8LIB/L, - =EG8LIB/M,=EG8LIB/N,=EG8LIB/O,=EG8LIB/P,=EG8LIB/Q,=EG8LP/YL,=EH8FLH/LH,=EH90IARU/8, + AM8,AN8,AO8,EA8,EB8,EC8,ED8,EE8,EF8,EG8,EH8,=AM70URE/8,=AN400L,=AN400U,=AO150ITU/8,=AO150U, + =AO4AAA/8,=EA1AK/8,=EA1AP/8,=EA1EHW/8,=EA1YO/8,=EA3RKB/8,=EA4BQ/8,=EA4ESI/8,=EA4SV/8,=EA4WT/8, + =EA4ZK/8,=EA5BK/8,=EA5HCC/8,=EA5RKL/8,=EA7JR/8,=EA8/DJ5AA/LH,=EA8AKG/F,=EA8AKG/G,=EA8DO/LP, + =EA8EE/L,=EA8TH/LP,=EA8URE/YOTA,=EA8URL/LH,=EA8URL/P/SBI,=EA9CI/8,=EA9CP/8,=EB2EMH/8,=EC1KR/8, + =EC8AFM/LH,=ED4R/8,=ED5RKL/8,=ED8BTM/C,=ED8BTM/E,=ED8BTM/J,=ED8BTM/L,=ED8BTM/S,=ED8GSA/J, + =ED8LIB/C,=ED8LIB/D,=ED8LIB/E,=ED8LIB/F,=ED8LIB/G,=ED8LIB/H,=ED8LIB/I,=ED8LIB/J,=ED8LIB/K, + =ED8LIB/N,=ED8LIB/O,=ED8LIB/Q,=ED8LPA/L,=ED8MCC/LH,=ED8OTA/D,=ED8OTA/H,=ED8PDC/E,=ED8PDC/K, + =ED8PDC/LP,=ED8PDC/O,=EF8LIB/N,=EG8LIB/C,=EG8LIB/D,=EG8LIB/E,=EG8LIB/F,=EG8LIB/G,=EG8LIB/H, + =EG8LIB/I,=EG8LIB/L,=EG8LIB/M,=EG8LIB/N,=EG8LIB/O,=EG8LIB/P,=EG8LIB/Q,=EG8LP/YL,=EH8FLH/LH, + =EH90IARU/8, =EA2TW/8,=EA3FNZ/8,=EA5EZ/8, =AO3MWC/8,=EA2SG/8,=EA4BFH/8,=EA4DE/8,=EA5RKB/8,=EA8BFH/P; Ceuta & Melilla: 33: 37: AF: 35.90: 5.27: -1.0: EA9: - AM9,AN9,AO9,EA9,EB9,EC9,ED9,EE9,EF9,EG9,EH9,=EA7URM/9,=EA9CE/C,=EA9CE/D,=EA9CE/E,=EA9CE/F, - =EA9CE/G,=EA9CE/H,=EA9CE/I,=EA9URC/PAZ,=EC7DZZ/9,=ED3AFR/9,=ED9CE/D,=ED9CE/E,=ED9CE/F, + AM9,AN9,AO9,EA9,EB9,EC9,ED9,EE9,EF9,EG9,EH9,=AM70URE/9,=EA4URE/9,=EA7URM/9,=EA9CE/C,=EA9CE/D, + =EA9CE/E,=EA9CE/F,=EA9CE/G,=EA9CE/H,=EA9CE/I,=EA9URC/PAZ,=EC7DZZ/9,=ED3AFR/9,=ED9CE/D,=ED9CE/E, + =ED9CE/F, =EA3EGB/9,=EA5RKB/9,=EA7UV/P,=EA9CD/M,=EA9CD/P,=EB9PH/P,=EC5ALJ/9, =EA5DCL/9,=EA7JTF/9,=EA9PD/M,=EA9PD/P,=EC7DRS/9; Ireland: 14: 27: EU: 53.13: 8.02: 0.0: EI: @@ -721,8 +728,8 @@ Iran: 21: 40: AS: 32.00: -53.00: -3.5: EP: Moldova: 16: 29: EU: 47.00: -29.00: -2.0: ER: ER,=ER3AC/FF,=ER3CR/FF,=ER4LX/FF; Estonia: 15: 29: EU: 59.00: -25.00: -2.0: ES: - ES,=ES/RX3AMI/LH,=ES/SA5FYR/LH, - =ES0TI/LH; + ES,=ES/SA5FYR/LH, + =ES/RX3AMI/LH,=ES0TI/LH; Ethiopia: 37: 48: AF: 9.00: -39.00: -3.0: ET: 9E,9F,ET,=ET3AA/YOTA; Belarus: 16: 29: EU: 54.00: -28.00: -2.0: EU: @@ -766,18 +773,19 @@ Austral Islands: 32: 63: OC: -23.37: 149.48: 10.0: FO/a: =FO/AC4LN/A,=FO/DF6IC,=FO/DJ4OI,=FO/DL1AWI,=FO/DL1IAN,=FO/DL3APO,=FO/DL3GA,=FO/DL7FT,=FO/DL9AWI, =FO/F6CTL,=FO/F8CFU,=FO/G3BJ,=FO/HG9B,=FO/HG9B/P,=FO/IK2GNW,=FO/JA8BMK,=FO/K7AR,=FO/OH6KN, =FO/ON4AXU/A,=FO/UT6UD,=FO0CLA/A,=FO0ERI,=FO0FLA,=FO0FRY,=FO0HWU,=FO0MOT/P,=FO0SEV,=FO0WEG, - =FO0WII,=FO5FD,=TX0HF,=TX3D,=TX5BTY,=TX5D,=TX5RV,=TX5SPA,=TX5T,=TX5W,=TX5Z,=TX6G; + =FO0WII,=FO5FD,=TX0HF,=TX2A,=TX3D,=TX5BTY,=TX5D,=TX5RV,=TX5SPA,=TX5T,=TX5W,=TX5Z,=TX6G; Clipperton Island: 07: 10: NA: 10.28: 109.22: 8.0: FO/c: =FO0/F8UFT,=FO0AAA,=TX5C,=TX5K,=TX5P; Marquesas Islands: 31: 63: OC: -8.92: 140.07: 9.5: FO/m: =FO/AC4LN/M,=FO/DJ7RJ,=FO/DL5XU,=FO/F6BFH/P,=FO/F6COW,=FO/F6EPY,=FO/F6GNZ,=FO/HA9G,=FO/IZ2ZTQ, =FO/JA0SC,=FO/JI1WTF,=FO/KA7OQQ,=FO/N7WLR,=FO/OH1RX,=FO/ON4AXU,=FO/ON4AXU/M,=FO/SP9FIH,=FO/W6TLD, =FO0ELY,=FO0POM,=FO0TOH,=FO5QS/M,=FO8RZ/P,=K7ST/FO,=TX0SIX,=TX4PG,=TX5A,=TX5SPM,=TX5VT,=TX7EU, - =TX7G,=TX7M; + =TX7G,=TX7M,=TX7T; St. Pierre & Miquelon: 05: 09: NA: 46.77: 56.20: 3.0: FP: FP,=TO200SPM,=TO2U,=TO5FP; Reunion Island: 39: 53: AF: -21.12: -55.48: -4.0: FR: - FR,=TO0FAR,=TO0R,=TO1PF,=TO1PF/P,=TO1TAAF,=TO2R,=TO2R/P,=TO2Z,=TO3R,=TO5M,=TO5R,=TO7CC,=TO90R; + FR,=TO0FAR,=TO0R,=TO19A,=TO1PF,=TO1PF/P,=TO1TAAF,=TO2R,=TO2R/P,=TO2Z,=TO3R,=TO5M,=TO5R,=TO7CC, + =TO90R; St. Martin: 08: 11: NA: 18.08: 63.03: 4.0: FS: FS,=TO1E,=TO2EME,=TO4X,=TO5D,=TO5SM,=TO5SM/P; Glorioso Islands: 39: 53: AF: -11.55: -47.28: -4.0: FT/g: @@ -808,130 +816,131 @@ England: 14: 27: EU: 52.77: 1.47: 0.0: G: =M6AIG/YL,=M6SUS/YL,=MQ6BWA/P; Isle of Man: 14: 27: EU: 54.20: 4.53: 0.0: GD: 2D,GD,GT,MD,MT,=2O0YLX,=2Q0YLX,=2R0IOM,=2V0IOM,=2V0YLX,=GB0AOA,=GB0BEA,=GB0IOM,=GB0MST,=GB100TT, - =GB19CIM,=GB1RT,=GB1SOI,=GB2IOM,=GB2MAD,=GB2RT,=GB2WB,=GB4COM,=GB4IOM,=GB4JDF,=GB4MGR,=GB4MNH, - =GB4SPT,=GB4WXM,=GB4WXM/P,=GB5LB,=GB5MOB,=GB5TD,=GD3JIU/2K,=GO0OUD,=GQ0OUD,=GR0AMD,=GR0HWA, - =GR0OUD,=GR6AFB,=GT3FLH/LGT,=GT3FLH/LT,=GT4IOM/LH,=GT8IOM/LH,=GV0OUD,=GV3YEO,=GV6AFB,=GV7HTG, - =MB100TT,=MO1CLV,=MQ1CLV,=MR0CCE,=MR3LJB,=MR3MLD,=MV3YLX; + =GB19CIM,=GB1MSG,=GB1RT,=GB1SOI,=GB2IOM,=GB2MAD,=GB2RT,=GB2WB,=GB4COM,=GB4IOM,=GB4JDF,=GB4MGR, + =GB4MNH,=GB4SPT,=GB4WXM,=GB4WXM/P,=GB5LB,=GB5MOB,=GB5TD,=GD3JIU/2K,=GO0OUD,=GQ0OUD,=GR0AMD, + =GR0HWA,=GR0OUD,=GR6AFB,=GT3FLH/LGT,=GT3FLH/LT,=GT4IOM/LH,=GT8IOM/LH,=GV0OUD,=GV3YEO,=GV6AFB, + =GV7HTG,=MB100TT,=MO1CLV,=MQ1CLV,=MR0CCE,=MR3LJB,=MR3MLD,=MV3YLX; Northern Ireland: 14: 27: EU: 54.73: 6.68: 0.0: GI: 2I,GI,GN,MI,MN,=2O0BAD,=2O0HBO,=2O0HRV,=2O0MFB,=2O0TWA,=2O0VEP,=2O0VGW,=2O0VIM,=2O0WAI,=2O0ZXM, =2Q0BSA,=2Q0ETB,=2Q0HRV,=2Q0MFB,=2Q0NIE,=2Q0SXG,=2Q0TWA,=2Q0VEP,=2Q0VIM,=2Q0ZXM,=2R0IRZ,=2R0IRZ/P, =2R0KPY,=2R0KYE,=2R0MFB,=2R0PTX,=2R0RMD,=2R0RVH,=2R0TCA,=2R0TMR,=2R0VAX,=2R0VEP,=2R0VIM,=2R0WAI, - =2R0WMN,=2V0CSB,=GB0ARM,=GB0AS,=GB0ATM,=GB0AVB,=GB0BIG,=GB0BMS,=GB0BPM,=GB0BTC,=GB0BVC,=GB0C, - =GB0CAS,=GB0CBS,=GB0COA,=GB0CSC,=GB0DDF,=GB0EBG,=GB0EG,=GB0FMF,=GB0FMH,=GB0GDI,=GB0GLS,=GB0GPF, - =GB0KKM,=GB0LNR,=GB0LSP,=GB0LVA,=GB0MAH,=GB0MAR,=GB0MFD,=GB0PAT,=GB0PSM,=GB0REL,=GB0RSL,=GB0SBG, - =GB0SPD,=GB0TCH,=GB0TGN,=GB0USR,=GB0VC,=GB0WOA,=GB100BOS,=GB100RAF,=GB100RNR,=GB106TBC,=GB150WCB, - =GB16SW,=GB1918EKN,=GB19CGI,=GB19CNI,=GB1AFP,=GB1BPM,=GB1DDG,=GB1IMD,=GB1RM,=GB1ROC,=GB1SPD, - =GB1SRI,=GB1UAS,=GB1WWC,=GB2AD,=GB2AD/P,=GB2AS,=GB2BCW,=GB2BDS,=GB2BOA,=GB2CA,=GB2CRU,=GB2DCI, - =GB2DMR,=GB2DPC,=GB2IL,=GB2LL,=GB2LOL,=GB2MAC,=GB2MRI,=GB2PP,=GB2PSW,=GB2REL,=GB2SDD,=GB2SPD, - =GB2SPR,=GB2STI,=GB2STP,=GB2SW,=GB2UAS,=GB3NGI,=GB4CSC,=GB4CTL,=GB4ONI,=GB4PS,=GB4SOS,=GB4SPD, - =GB4UAS,=GB50AAD,=GB50CSC,=GB5BIG,=GB5BL,=GB5BL/LH,=GB5DPR,=GB5OMU,=GB5SPD,=GB6EPC,=GB6VCB, - =GB8BKY,=GB8BRM,=GB8DS,=GB8EGT,=GB8GLM,=GB8ROC,=GB8SPD,=GB90RSGB/82,=GB90SOM,=GB9RAF,=GB9SPD, - =GN0LIX/LH,=GN4GTY/LH,=GO0AQD,=GO0BJH,=GO0DUP,=GO3KVD,=GO3MMF,=GO3SG,=GO4DOH,=GO4GID,=GO4GUH, - =GO4LKG,=GO4NKB,=GO4ONL,=GO4OYM,=GO4SRQ,=GO4SZW,=GO6MTL,=GO7AXB,=GO7KMC,=GO8YYM,=GQ0AQD,=GQ0BJG, - =GQ0NCA,=GQ0RQK,=GQ0TJV,=GQ0UVD,=GQ1CET,=GQ3KVD,=GQ3MMF,=GQ3SG,=GQ3UZJ,=GQ3XRQ,=GQ4DOH,=GQ4GID, - =GQ4GUH,=GQ4JTF,=GQ4LKG,=GQ4LXL,=GQ4NKB,=GQ4ONL,=GQ4OYM,=GQ4SZW,=GQ6JPO,=GQ6MTL,=GQ7AXB,=GQ7JYK, - =GQ7KMC,=GQ8RQI,=GQ8YYM,=GR0BJH,=GR0BRO,=GR0DVU,=GR0RQK,=GR0RWO,=GR0UVD,=GR1CET,=GR3GTR,=GR3KDR, - =GR3SG,=GR3WEM,=GR4AAM,=GR4DHW,=GR4DOH,=GR4FUE,=GR4FUM,=GR4GID,=GR4GOS,=GR4GUH,=GR4KQU,=GR4LXL, - =GR4NKB,=GR6JPO,=GR7AXB,=GR7KMC,=GR8RKC,=GR8RQI,=GR8YYM,=GV1BZT,=GV3KVD,=GV3SG,=GV4FUE,=GV4GUH, - =GV4JTF,=GV4LXL,=GV4SRQ,=GV4WVN,=GV7AXB,=GV7THH,=MI5AFK/2K,=MN0NID/LH,=MO0ALS,=MO0BDZ,=MO0CBH, - =MO0IOU,=MO0IRZ,=MO0JFC,=MO0JFC/P,=MO0JML,=MO0JST,=MO0KYE,=MO0LPO,=MO0MOD,=MO0MOD/P,=MO0MSR, - =MO0MVP,=MO0RRE,=MO0RUC,=MO0RYL,=MO0TGO,=MO0VAX,=MO0ZXZ,=MO3RLA,=MO6AOX,=MO6NIR,=MO6TUM,=MO6WAG, - =MO6WDB,=MO6YDR,=MQ0ALS,=MQ0BDZ,=MQ0BPB,=MQ0GGB,=MQ0IRZ,=MQ0JFC,=MQ0JST,=MQ0KAM,=MQ0KYE,=MQ0MOD, - =MQ0MSR,=MQ0MVP,=MQ0RMD,=MQ0RRE,=MQ0RUC,=MQ0RYL,=MQ0TGO,=MQ0VAX,=MQ0ZXZ,=MQ3GHW,=MQ3RLA,=MQ3STV, - =MQ5AFK,=MQ6AOX,=MQ6BJG,=MQ6GDN,=MQ6WAG,=MQ6WDB,=MQ6WGM,=MR0GDO,=MR0GGB,=MR0JFC,=MR0KQU,=MR0LPO, - =MR0MOD,=MR0MSR,=MR0MVP,=MR0RUC,=MR0SAI,=MR0SMK,=MR0TFK,=MR0TLG,=MR0TMW,=MR0VAX,=MR0WWB,=MR1CCU, - =MR3RLA,=MR3TFF,=MR3WHM,=MR5AMO,=MR6CCU,=MR6CWC,=MR6GDN,=MR6MME,=MR6MRJ,=MR6OKS,=MR6OLA,=MR6PUX, - =MR6WAG,=MR6XGZ,=MV0ALS,=MV0GGB,=MV0IOU,=MV0JFC,=MV0JLC,=MV0MOD,=MV0MSR,=MV0MVP,=MV0TGO,=MV0VAX, - =MV0WGM,=MV0ZAO,=MV1VOX,=MV6DTE,=MV6GTY,=MV6NIR,=MV6TLG; + =2R0WMN,=2V0CSB,=GB0ARM,=GB0AS,=GB0AVB,=GB0BIG,=GB0BMS,=GB0BPM,=GB0BTC,=GB0BVC,=GB0C,=GB0CAS, + =GB0CBS,=GB0COA,=GB0CSC,=GB0DDF,=GB0EBG,=GB0EG,=GB0FMF,=GB0FMH,=GB0GDI,=GB0GLS,=GB0GPF,=GB0KKM, + =GB0LNR,=GB0LSP,=GB0LVA,=GB0MAH,=GB0MAR,=GB0MFD,=GB0PAT,=GB0PSM,=GB0REL,=GB0RSL,=GB0SBG,=GB0SPD, + =GB0TCH,=GB0TGN,=GB0USR,=GB0VC,=GB0WOA,=GB100BOS,=GB100RNR,=GB106TBC,=GB150WCB,=GB16SW,=GB1918EKN, + =GB19CGI,=GB19CNI,=GB1AFP,=GB1BPM,=GB1DDG,=GB1IMD,=GB1RM,=GB1ROC,=GB1SPD,=GB1SRI,=GB1UAS,=GB1WWC, + =GB2AD,=GB2AD/P,=GB2AS,=GB2BCW,=GB2BDS,=GB2BOA,=GB2CA,=GB2CRU,=GB2DCI,=GB2DMR,=GB2DPC,=GB2IL, + =GB2LL,=GB2LOL,=GB2MAC,=GB2MRI,=GB2PP,=GB2PSW,=GB2REL,=GB2SDD,=GB2SPD,=GB2SPR,=GB2STI,=GB2STP, + =GB2SW,=GB2UAS,=GB3NGI,=GB4CSC,=GB4CTL,=GB4ONI,=GB4PS,=GB4SOS,=GB4SPD,=GB4UAS,=GB50AAD,=GB50CSC, + =GB5BIG,=GB5BL,=GB5BL/LH,=GB5DPR,=GB5OMU,=GB5SPD,=GB6EPC,=GB6VCB,=GB8BKY,=GB8BRM,=GB8DS,=GB8EGT, + =GB8GLM,=GB8ROC,=GB8SPD,=GB90RSGB/82,=GB90SOM,=GB9RAF,=GB9SPD,=GN0LIX/LH,=GN4GTY/LH,=GO0AQD, + =GO0BJH,=GO0DUP,=GO3KVD,=GO3MMF,=GO3SG,=GO4DOH,=GO4GID,=GO4GUH,=GO4LKG,=GO4NKB,=GO4ONL,=GO4OYM, + =GO4SRQ,=GO4SZW,=GO6MTL,=GO7AXB,=GO7KMC,=GO8YYM,=GQ0AQD,=GQ0BJG,=GQ0NCA,=GQ0RQK,=GQ0TJV,=GQ0UVD, + =GQ1CET,=GQ3KVD,=GQ3MMF,=GQ3SG,=GQ3UZJ,=GQ3XRQ,=GQ4DOH,=GQ4GID,=GQ4GUH,=GQ4JTF,=GQ4LKG,=GQ4LXL, + =GQ4NKB,=GQ4ONL,=GQ4OYM,=GQ4SZW,=GQ6JPO,=GQ6MTL,=GQ7AXB,=GQ7JYK,=GQ7KMC,=GQ8RQI,=GQ8YYM,=GR0BJH, + =GR0BRO,=GR0DVU,=GR0RQK,=GR0RWO,=GR0UVD,=GR1CET,=GR3GTR,=GR3KDR,=GR3SG,=GR3WEM,=GR4AAM,=GR4DHW, + =GR4DOH,=GR4FUE,=GR4FUM,=GR4GID,=GR4GOS,=GR4GUH,=GR4KQU,=GR4LXL,=GR4NKB,=GR6JPO,=GR7AXB,=GR7KMC, + =GR8RKC,=GR8RQI,=GR8YYM,=GV1BZT,=GV3KVD,=GV3SG,=GV4FUE,=GV4GUH,=GV4JTF,=GV4LXL,=GV4SRQ,=GV4WVN, + =GV7AXB,=GV7THH,=MI5AFK/2K,=MN0NID/LH,=MO0ALS,=MO0BDZ,=MO0CBH,=MO0IOU,=MO0IRZ,=MO0JFC,=MO0JFC/P, + =MO0JML,=MO0JST,=MO0KYE,=MO0LPO,=MO0MOD,=MO0MOD/P,=MO0MSR,=MO0MVP,=MO0RRE,=MO0RUC,=MO0RYL,=MO0TGO, + =MO0VAX,=MO0ZXZ,=MO3RLA,=MO6AOX,=MO6NIR,=MO6TUM,=MO6WAG,=MO6WDB,=MO6YDR,=MQ0ALS,=MQ0BDZ,=MQ0BPB, + =MQ0GGB,=MQ0IRZ,=MQ0JFC,=MQ0JST,=MQ0KAM,=MQ0KYE,=MQ0MOD,=MQ0MSR,=MQ0MVP,=MQ0RMD,=MQ0RRE,=MQ0RUC, + =MQ0RYL,=MQ0TGO,=MQ0VAX,=MQ0ZXZ,=MQ3GHW,=MQ3RLA,=MQ3STV,=MQ5AFK,=MQ6AOX,=MQ6BJG,=MQ6GDN,=MQ6WAG, + =MQ6WDB,=MQ6WGM,=MR0GDO,=MR0GGB,=MR0JFC,=MR0KQU,=MR0LPO,=MR0MOD,=MR0MSR,=MR0MVP,=MR0RUC,=MR0SAI, + =MR0SMK,=MR0TFK,=MR0TLG,=MR0TMW,=MR0VAX,=MR0WWB,=MR1CCU,=MR3RLA,=MR3TFF,=MR3WHM,=MR5AMO,=MR6CCU, + =MR6CWC,=MR6GDN,=MR6MME,=MR6MRJ,=MR6OKS,=MR6OLA,=MR6PUX,=MR6WAG,=MR6XGZ,=MV0ALS,=MV0GGB,=MV0IOU, + =MV0JFC,=MV0JLC,=MV0MOD,=MV0MSR,=MV0MVP,=MV0TGO,=MV0VAX,=MV0WGM,=MV0ZAO,=MV1VOX,=MV6DTE,=MV6GTY, + =MV6NIR,=MV6TLG; Jersey: 14: 27: EU: 49.22: 2.18: 0.0: GJ: 2J,GH,GJ,MH,MJ,=2R0ODX,=GB0JSA,=GB19CJ,=GB2BYL,=GB2JSA,=GB50JSA,=GB5OJR,=GB8LMI,=GJ3DVC/L, =GJ6WRI/LH,=GJ8PVL/LH,=GO8PVL,=GQ8PVL,=GR6TMM,=MO0ASP,=MQ0ASP,=MR0ASP,=MR0RZD,=MV0ASP; Shetland Islands: 14: 27: EU: 60.50: 1.50: 0.0: *GM/s: =2M0BDR,=2M0BDT,=2M0CPN,=2M0GFC,=2M0SEG,=2M0SPX,=2M0VIK,=2M0ZET,=2M1ANT,=2M1ASQ,=2M1ODL,=G0FBJ, - =GB0BL,=GB100ZET,=GB2AES,=GB2CAS,=GB2ELH,=GB2ELH/LH,=GB2HMC,=GB2IGS,=GB2LHI,=GB2NBC,=GB2QM,=GB2SB, - =GB2SLH,=GB2SR,=GB2SUM,=GB2WG,=GB3LER,=GB3LER/B,=GB4LER,=GM0AVR,=GM0CXQ,=GM0CYJ,=GM0DJI,=GM0EKM, - =GM0GFL,=GM0GFL/P,=GM0ILB,=GM0JDB,=GM0VFA,=GM1BYL,=GM1CBQ,=GM1FGN,=GM1KKI,=GM1MXN,=GM1ZNR,=GM3KLA, - =GM3KZH,=GM3RFR,=GM3SJA,=GM3SKN,=GM3TXF/P,=GM3WCH,=GM3WHT,=GM3ZET,=GM3ZXH,=GM4AFF/P,=GM4AGX, - =GM4CHX/P,=GM4ENK,=GM4FNE,=GM4GPN,=GM4GPP,=GM4GQD,=GM4GQM,=GM4IPK,=GM4JPI,=GM4LBE,=GM4LER,=GM4PXG, - =GM4S,=GM4SLV,=GM4SSA,=GM4WXQ,=GM4ZHL,=GM6RQW,=GM6RTO,=GM6VZB,=GM6WVI,=GM6YQA,=GM7AFE,=GM7GWW, - =GM7RKD,=GM8LNH,=GM8MMA,=GM8YEC,=GS0AAA,=GS0GRC,=GS3BSQ,=GS3ZET,=GS7V,=GS8YL,=MA0XAU,=MA1FJM, - =MA6PTE,=MM/DJ6OZ,=MM/OK1HDU,=MM/OK7U,=MM/PA9D,=MM/PF9DC,=MM/W5ZE/P,=MM0/DJ6AU,=MM0/PA8MO,=MM0ECG, - =MM0KAL,=MM0LON,=MM0LON/M,=MM0LSM,=MM0NQY,=MM0SHF/P,=MM0VIK,=MM0XAU,=MM0ZAL,=MM0ZCG,=MM0ZRC, - =MM1FJM,=MM3VQO,=MM3ZET,=MM5PSL,=MM5PSL/P,=MM5YLO,=MM5YLO/P,=MM6ACW,=MM6BDU,=MM6BZQ,=MM6IKB, - =MM6IMB,=MM6MFA,=MM6PTE,=MM6SJK,=MM6YLO,=MM6ZBG,=MM6ZDW,=MM8A,=MO5PSL,=MQ5PSL,=MR5PSL,=MS0OXE, - =MS0ZCG,=MS0ZET; + =GB0BL,=GB0DAW,=GB100ZET,=GB2AES,=GB2CAS,=GB2DAW,=GB2ELH,=GB2ELH/LH,=GB2HMC,=GB2IGS,=GB2LHI, + =GB2NBC,=GB2QM,=GB2SB,=GB2SLH,=GB2SR,=GB2SUM,=GB2WG,=GB3LER,=GB3LER/B,=GB4LER,=GM0AVR,=GM0CXQ, + =GM0CYJ,=GM0DJI,=GM0EKM,=GM0GFL,=GM0GFL/P,=GM0ILB,=GM0JDB,=GM0VFA,=GM1BYL,=GM1CBQ,=GM1FGN,=GM1KKI, + =GM1MXN,=GM1ZNR,=GM3KLA,=GM3KZH,=GM3RFR,=GM3SJA,=GM3SKN,=GM3TXF/P,=GM3WCH,=GM3WHT,=GM3ZET,=GM3ZXH, + =GM4AFF/P,=GM4AGX,=GM4CHX/P,=GM4ENK,=GM4FNE,=GM4GPN,=GM4GPP,=GM4GQD,=GM4GQM,=GM4IPK,=GM4JPI, + =GM4LBE,=GM4LER,=GM4PXG,=GM4S,=GM4SLV,=GM4SSA,=GM4WXQ,=GM4ZHL,=GM6RQW,=GM6RTO,=GM6VZB,=GM6WVI, + =GM6YQA,=GM7AFE,=GM7GWW,=GM7RKD,=GM8LNH,=GM8MMA,=GM8YEC,=GS0AAA,=GS0GRC,=GS3BSQ,=GS3ZET,=GS7V, + =GS8YL,=MA0XAU,=MA1FJM,=MA6PTE,=MM/DJ6OZ,=MM/OK1HDU,=MM/OK7U,=MM/PA9D,=MM/PF9DC,=MM/W5ZE/P, + =MM0/DJ6AU,=MM0/PA8MO,=MM0ECG,=MM0KAL,=MM0LON,=MM0LON/M,=MM0LSM,=MM0NQY,=MM0SHF/P,=MM0VIK,=MM0XAU, + =MM0ZAL,=MM0ZCG,=MM0ZRC,=MM1FJM,=MM3VQO,=MM3ZET,=MM5PSL,=MM5PSL/P,=MM5YLO,=MM5YLO/P,=MM6ACW, + =MM6BDU,=MM6BZQ,=MM6IKB,=MM6IMB,=MM6MFA,=MM6PTE,=MM6SJK,=MM6YLO,=MM6ZBG,=MM6ZDW,=MM8A,=MO5PSL, + =MQ5PSL,=MR5PSL,=MS0OXE,=MS0ZCG,=MS0ZET; Scotland: 14: 27: EU: 56.82: 4.18: 0.0: GM: 2A,2M,GM,GS,MA,MM,MS,=2O0BSE,=2O0BZB,=2O0HJS,=2O0IMP,=2O0IOB,=2O0IVG,=2O0LIM,=2O0LJM,=2O0TOK, =2O1MIC,=2O1SJB,=2Q0BSE,=2Q0BZB,=2Q0FYG,=2Q0HJS,=2Q0IMP,=2Q0IOB,=2Q0JOK,=2Q0LDO,=2Q0TAX,=2Q0TOK, =2Q0YCG,=2Q1MIC,=2Q1SJB,=2R0BOO,=2R0BSE,=2R0BXN,=2R0BZB,=2R0DES,=2R0DXR,=2R0FYG,=2R0GLI,=2R0HJS, =2R0IMP,=2R0IOB,=2R0ISM,=2R0JVR,=2R0KAU,=2R0KAU/P,=2R0NCM,=2R0OXX,=2R0YCG,=2R0ZPS,=2R1MIC,=2R1SJB, =2V0GUL,=2V0IVG,=2V0JCH,=2V0KAU,=2V0TAX,=2V1HFE,=2V1MIC,=2V1SJB,=G0FBJ,=GA6NX/LH,=GB0AYR,=GB0BAJ, - =GB0BCG,=GB0BCK,=GB0BD,=GB0BDC,=GB0BL,=GB0BNA,=GB0BNC,=GB0BOL,=GB0BSS,=GB0BWT,=GB0CCF,=GB0CHL, - =GB0CLH,=GB0CML,=GB0CNL,=GB0CWF,=GB0CWS,=GB0DBS,=GB0DHL,=GB0DPK,=GB0EPC,=GB0FFS,=GB0FSG,=GB0GDS, - =GB0GDS/J,=GB0GGR,=GB0GRN,=GB0HHW,=GB0HLD,=GB0JOG,=GB0KEY,=GB0KGS,=GB0KKS,=GB0KLT,=GB0LCS,=GB0LCW, - =GB0LTM,=GB0MLH,=GB0MLM,=GB0MOG,=GB0MOL,=GB0MSL,=GB0MUL,=GB0NGG,=GB0NHL,=GB0NHL/LH,=GB0NRL, - =GB0OYT,=GB0PLS,=GB0POS,=GB0PPE,=GB0PSW,=GB0RGC,=GB0SAA,=GB0SBC,=GB0SCD,=GB0SFM,=GB0SHP,=GB0SI, - =GB0SK,=GB0SKG,=GB0SKY,=GB0SRC,=GB0SSB,=GB0TH,=GB0THL,=GB0TNL,=GB0TTS,=GB0WRH,=GB100MAS,=GB100MUC, - =GB100ZET,=GB10SP,=GB150NRL,=GB18FIFA,=GB19CGM,=GB19CS,=GB1AJ,=GB1ASC,=GB1ASH,=GB1BD,=GB1BOL, - =GB1CFL,=GB1DHL,=GB1FB,=GB1FRS,=GB1FS,=GB1FVS,=GB1FVT,=GB1GEO,=GB1HRS,=GB1KGG,=GB1KLD,=GB1LAY, - =GB1LGG,=GB1LL,=GB1MAY,=GB1MSG,=GB1NHL,=GB1OL,=GB1OL/LH,=GB1PC,=GB1RB,=GB1RHU,=GB1SLH,=GB1TAY, - =GB1WLG,=GB250RB,=GB2AES,=GB2AGG,=GB2AL,=GB2AST,=GB2ATC,=GB2AYR,=GB2BAJ,=GB2BHM,=GB2BHS,=GB2BMJ, - =GB2BOL,=GB2CAS,=GB2CHC,=GB2CM,=GB2CMA,=GB2CVL,=GB2DAS,=GB2DHS,=GB2DL,=GB2DRC,=GB2DT,=GB2DTM, - =GB2ELH,=GB2ELH/LH,=GB2EPC,=GB2FBM,=GB2FSM,=GB2FSW,=GB2GEO,=GB2GKR,=GB2GNL,=GB2GNL/LH,=GB2GTM, - =GB2HLB,=GB2HMC,=GB2HRH,=GB2IGB,=GB2IGS,=GB2IMG,=GB2IMM,=GB2INV,=GB2IOT,=GB2JCM,=GB2KDR,=GB2KGB, - =GB2KW,=GB2LBN,=GB2LBN/LH,=GB2LCL,=GB2LCP,=GB2LCT,=GB2LDG,=GB2LG,=GB2LGB,=GB2LHI,=GB2LK,=GB2LK/LH, - =GB2LMG,=GB2LP,=GB2LS,=GB2LS/LH,=GB2LSS,=GB2LT,=GB2LT/LH,=GB2LXX,=GB2M,=GB2MAS,=GB2MBB,=GB2MDG, - =GB2MN,=GB2MOF,=GB2MSL,=GB2MUC,=GB2MUL,=GB2NBC,=GB2NEF,=GB2NL,=GB2OL,=GB2OWM,=GB2PBF,=GB2PG, - =GB2QM,=GB2RB,=GB2RDR,=GB2RRL,=GB2RWW,=GB2SAA,=GB2SAM,=GB2SAS,=GB2SB,=GB2SBG,=GB2SHL/LH,=GB2SKG, - =GB2SLH,=GB2SMM,=GB2SOH,=GB2SQN,=GB2SR,=GB2SSB,=GB2SUM,=GB2SWF,=GB2TDS,=GB2THL,=GB2TNL,=GB2VCB, - =GB2VEF,=GB2WBF,=GB2WG,=GB2WLS,=GB2YLS,=GB2ZE,=GB3ANG,=GB3GKR,=GB3GM,=GB3LER,=GB3LER/B,=GB3ORK, - =GB3ORK/B,=GB3SWF,=GB3WOI,=GB4AAS,=GB4AST,=GB4BBR,=GB4BG,=GB4CGS,=GB4CMA,=GB4DAS,=GB4DHX,=GB4DTD, - =GB4DUK,=GB4EPC,=GB4GD,=GB4GDS,=GB4GS,=GB4IE,=GB4JCM,=GB4JPJ,=GB4JYS,=GB4LER,=GB4MSE,=GB4NFE, - =GB4OL,=GB4PAS,=GB4SK,=GB4SKO,=GB4SLH,=GB4SMM,=GB4SRO,=GB4SWF,=GB50FVS,=GB50GDS,=GB50JS,=GB50WAB, - =GB5AG,=GB5AST,=GB5BBS,=GB5BOH,=GB5C,=GB5CCC,=GB5CS,=GB5DHL,=GB5DX,=GB5EMF,=GB5FHC,=GB5FLM,=GB5JS, - =GB5LTH,=GB5RO,=GB5RO/LH,=GB5RR,=GB5SI,=GB5TAM,=GB5TI,=GB60CRB,=GB6BEN,=GB6TAA,=GB6WW,=GB75CC, - =GB75GD,=GB80GD,=GB8AYR,=GB8CSL,=GB8FSG,=GB8RU,=GB8RUM,=GB90RSGB/11,=GB90RSGB/12,=GB90RSGB/21, - =GB90RSGB/22,=GB90RSGB/23,=GB999SPC,=GG100AGG,=GG100GA,=GG100GCC,=GG100GGP,=GG100GGR,=GG100GLD, - =GG100SBG,=GM/DL5SE/LH,=GM0AZC/2K,=GM0DHZ/P,=GM0GFL/P,=GM0KTO/2K,=GM0MUN/2K,=GM0SGB/P,=GM0WUX/2K, - =GM3JIJ/2K,=GM3OFT/P,=GM3TKV/LH,=GM3TTC/P,=GM3TXF/P,=GM3USR/P,=GM3VLB/P,=GM4AFF/P,=GM4CHX/2K, - =GM4CHX/P,=GM4WSB/M,=GM4WSB/P,=GM4ZVD/P,=GM6WRW/P,=GO0AEG,=GO0AIR,=GO0BKC,=GO0DBW,=GO0DBW/M, - =GO0DEQ,=GO0GMN,=GO0OGN,=GO0SYY,=GO0TUB,=GO0VRP,=GO0WEZ,=GO1BAN,=GO1BKF,=GO1MQE,=GO1TBW,=GO2MP, - =GO3HVK,=GO3JIJ,=GO3NIG,=GO3VTB,=GO4BLO,=GO4CAU,=GO4CFS,=GO4CHX,=GO4CXM,=GO4DLG,=GO4EMX,=GO4FAM, - =GO4FAU,=GO4JOJ,=GO4JPZ,=GO4JR,=GO4MOX,=GO4MSL,=GO4PRB,=GO4UBJ,=GO4VTB,=GO4WZG,=GO4XQJ,=GO6JEP, - =GO6JRX,=GO6KON,=GO6LYJ,=GO6VCV,=GO7GAX,=GO7GDE,=GO7HUD,=GO7TUD,=GO7WEF,=GO8CBQ,=GO8MHU,=GO8SVB, - =GO8TTD,=GQ0AEG,=GQ0AIR,=GQ0BKC,=GQ0BWR,=GQ0DBW,=GQ0DEQ,=GQ0DUX,=GQ0FNE,=GQ0GMN,=GQ0HUO,=GQ0KWL, - =GQ0MUN,=GQ0NTL,=GQ0OGN,=GQ0RNR,=GQ0TKV/P,=GQ0VRP,=GQ0WEZ,=GQ0WNR,=GQ1BAN,=GQ1BKF,=GQ1MQE,=GQ1TBW, - =GQ3JIJ,=GQ3JQJ,=GQ3NIG,=GQ3NTL,=GQ3TKP,=GQ3TKP/P,=GQ3TKV,=GQ3TKV/P,=GQ3VTB,=GQ3WUX,=GQ3ZBE, - =GQ4AGG,=GQ4BAE,=GQ4BLO,=GQ4CAU,=GQ4CFS,=GQ4CHX,=GQ4CHX/P,=GQ4CXM,=GQ4DLG,=GQ4ELV,=GQ4EMX,=GQ4FAU, - =GQ4JOJ,=GQ4JPZ,=GQ4JR,=GQ4MSL,=GQ4OBG,=GQ4PRB,=GQ4UIB,=GQ4UPL,=GQ4VTB,=GQ4WZG,=GQ4XQJ,=GQ4YMM, - =GQ6JEP,=GQ6JRX,=GQ6KON,=GQ6LYJ,=GQ7GAX,=GQ7GDE,=GQ7HUD,=GQ7TUD,=GQ7UED,=GQ7WEF,=GQ8CBQ,=GQ8MHU, - =GQ8PLR,=GQ8SVB,=GQ8TTD,=GR0AXY,=GR0CDV,=GR0DBW,=GR0EKM,=GR0GMN,=GR0GRD,=GR0HPK,=GR0HPL,=GR0HUO, - =GR0OGN,=GR0PNS,=GR0SYV,=GR0TTV,=GR0TUB,=GR0UKZ,=GR0VRP,=GR0WED,=GR0WNR,=GR150NIB,=GR1BAN,=GR1MWK, - =GR1TBW,=GR1ZIV,=GR3JFG,=GR3MZX,=GR3NIG,=GR3OFT,=GR3PPE,=GR3PYU,=GR3VAL,=GR3VTB,=GR3WFJ,=GR3YXJ, - =GR3ZDH,=GR4BDJ,=GR4BLO,=GR4CAU,=GR4CCN,=GR4CFS,=GR4CMI,=GR4CXM,=GR4DLG,=GR4EMX,=GR4EOU,=GR4FQE, - =GR4GIF,=GR4JOJ,=GR4NSZ,=GR4PRB,=GR4SQM,=GR4VTB,=GR4XAW,=GR4XMD,=GR4XQJ,=GR4YMM,=GR6JEP,=GR6JNJ, - =GR7AAJ,=GR7GAX,=GR7GDE,=GR7GMC,=GR7HHB,=GR7HUD,=GR7LNO,=GR7NZI,=GR7TUD,=GR7USC,=GR7VSB,=GR8CBQ, - =GR8KJO,=GR8KPH,=GR8MHU,=GR8OFQ,=GR8SVB,=GS4WAB/P,=GV0DBW,=GV0GMN,=GV0GRD,=GV0LZE,=GV0OBX,=GV0OGN, - =GV0SYV,=GV0VRP,=GV1BAN,=GV3EEW,=GV3JIJ,=GV3NHQ,=GV3NIG,=GV3NKG,=GV3NNZ,=GV3PIP,=GV3ULP,=GV3VTB, - =GV4BLO,=GV4EMX,=GV4HRJ,=GV4ILS,=GV4JOJ,=GV4KLN,=GV4LVW,=GV4PRB,=GV4VTB,=GV4XQJ,=GV6KON,=GV7DHA, - =GV7GDE,=GV7GMC,=GV8AVM,=GV8DPV,=GV8LYS,=MB18FIFA,=MM/DH5JBR/P,=MM/DJ4OK/M,=MM/DJ8OK/M, - =MM/DL5SE/LH,=MM/F5BLC/P,=MM/F5LMJ/P,=MM/HB9IAB/P,=MM/KE5TF/P,=MM/N5ET/P,=MM/OK1FZM/P,=MM/W5ZE/P, - =MM0BNN/LH,=MM0BQI/2K,=MM0BQN/2K,=MM0BYE/2K,=MM0DFV/P,=MM0LON/M,=MM0SHF/P,=MM0YHB/P,=MM0ZOL/LH, - =MM5PSL/P,=MM5YLO/P,=MO0BFF,=MO0CWJ,=MO0CYR,=MO0DBC,=MO0DNX,=MO0FMF,=MO0GXQ,=MO0HZT,=MO0JST/P, - =MO0KJG,=MO0KSS,=MO0NFC,=MO0SGQ,=MO0SJT,=MO0TGB,=MO0TSG,=MO0WKC,=MO0XXW,=MO0ZBH,=MO1AWV,=MO1HMV, - =MO3BCA,=MO3BRR,=MO3GPL,=MO3OQR,=MO3TUP,=MO3UVL,=MO3YHA,=MO3YMU,=MO3ZRF,=MO5PSL,=MO6BJJ,=MO6CCS, - =MO6CHM,=MO6CRQ,=MO6CRQ/M,=MO6DGZ,=MO6HUT,=MO6KAU,=MO6KAU/M,=MO6KSJ,=MO6MCV,=MO6SRL,=MO6TEW, - =MQ0BNN/P,=MQ0BQM,=MQ0BRG,=MQ0CIN,=MQ0CXA,=MQ0CYR,=MQ0DNX,=MQ0DXD,=MQ0EQE,=MQ0FMF,=MQ0GXQ,=MQ0GYX, - =MQ0GYX/P,=MQ0KJG,=MQ0KSS,=MQ0LEN,=MQ0NFC,=MQ0NJC,=MQ0SJT,=MQ0TSG,=MQ0WKC,=MQ0XXW,=MQ0ZBH,=MQ1AWV, - =MQ1HMV,=MQ1JWF,=MQ3BCA,=MQ3BRR,=MQ3ERZ,=MQ3FET,=MQ3OVK,=MQ3SVK,=MQ3UIX,=MQ3UVL,=MQ3YHA,=MQ3YMU, - =MQ3ZRF,=MQ5PSL,=MQ6AQM,=MQ6BJJ,=MQ6CCS,=MQ6CHM,=MQ6CRQ,=MQ6DGZ,=MQ6HUT,=MQ6KAJ,=MQ6KAU,=MQ6KSJ, - =MQ6KUA,=MQ6LMP,=MQ6MCV,=MR0BQN,=MR0CWB,=MR0CXA,=MR0DHQ,=MR0DWF,=MR0DXD,=MR0DXH,=MR0EPC,=MR0EQE, - =MR0FME,=MR0FMF,=MR0GCF,=MR0GGG,=MR0GGI,=MR0GOR,=MR0HAI,=MR0HVU,=MR0OIL,=MR0POD,=MR0PSL,=MR0RDM, - =MR0SGQ,=MR0SJT,=MR0TAI,=MR0TSG,=MR0TSS,=MR0VTV,=MR0WEI,=MR0XAF,=MR0XXP,=MR0XXW,=MR1AWV,=MR1HMV, - =MR1JWF,=MR1VTB,=MR3AWA,=MR3AWD,=MR3BRR,=MR3PTS,=MR3UIX,=MR3UVL,=MR3WJZ,=MR3XGP,=MR3YHA,=MR3YPH, - =MR3ZCS,=MR5PSL,=MR6AHB,=MR6ARN,=MR6ATU,=MR6CHM,=MR6CTH,=MR6CTL,=MR6HFC,=MR6MCV,=MR6RLL,=MR6SSI, - =MR6TMS,=MV0DXH,=MV0FME,=MV0FMF,=MV0GHM,=MV0HAR,=MV0LGS,=MV0NFC,=MV0NJS,=MV0SGQ,=MV0SJT,=MV0XXW, - =MV1VTB,=MV3BRR,=MV3CVB,=MV3YHA,=MV3YMU,=MV5PSL,=MV6BJJ,=MV6KSJ,=MV6NRQ; + =GB0BCG,=GB0BCK,=GB0BD,=GB0BDC,=GB0BL,=GB0BNA,=GB0BNC,=GB0BOC,=GB0BOL,=GB0BSS,=GB0BWT,=GB0CCF, + =GB0CHL,=GB0CLH,=GB0CML,=GB0CNL,=GB0CWF,=GB0CWS,=GB0DAW,=GB0DBS,=GB0DHL,=GB0DPK,=GB0EPC,=GB0FFS, + =GB0FSG,=GB0GDS,=GB0GDS/J,=GB0GGR,=GB0GRN,=GB0HHW,=GB0HLD,=GB0JOG,=GB0KEY,=GB0KGS,=GB0KKS,=GB0KLT, + =GB0LCS,=GB0LCW,=GB0LTM,=GB0MLH,=GB0MLM,=GB0MOG,=GB0MOL,=GB0MSL,=GB0MUL,=GB0NGG,=GB0NHL, + =GB0NHL/LH,=GB0NRL,=GB0OYT,=GB0PLS,=GB0POS,=GB0PPE,=GB0PSW,=GB0RGC,=GB0SAA,=GB0SBC,=GB0SCD, + =GB0SFM,=GB0SHP,=GB0SI,=GB0SK,=GB0SKG,=GB0SKY,=GB0SRC,=GB0SSB,=GB0TH,=GB0THL,=GB0TNL,=GB0TTS, + =GB0WRH,=GB100MAS,=GB100MUC,=GB100ZET,=GB10SP,=GB150NRL,=GB18FIFA,=GB19CGM,=GB19CS,=GB1AJ,=GB1ASC, + =GB1ASH,=GB1BD,=GB1BOL,=GB1CFL,=GB1DHL,=GB1FB,=GB1FRS,=GB1FS,=GB1FVS,=GB1FVT,=GB1GEO,=GB1HRS, + =GB1KGG,=GB1KLD,=GB1LAY,=GB1LGG,=GB1LL,=GB1MAY,=GB1NHL,=GB1OL,=GB1OL/LH,=GB1PC,=GB1RB,=GB1RHU, + =GB1SLH,=GB1TAY,=GB1WLG,=GB250RB,=GB2AES,=GB2AGG,=GB2AL,=GB2AST,=GB2ATC,=GB2AYR,=GB2BAJ,=GB2BHM, + =GB2BHS,=GB2BMJ,=GB2BOL,=GB2CAS,=GB2CHC,=GB2CM,=GB2CMA,=GB2CVL,=GB2DAS,=GB2DAW,=GB2DHS,=GB2DL, + =GB2DRC,=GB2DT,=GB2DTM,=GB2ELH,=GB2ELH/LH,=GB2EPC,=GB2FBM,=GB2FSM,=GB2FSW,=GB2GEO,=GB2GKR,=GB2GNL, + =GB2GNL/LH,=GB2GTM,=GB2HLB,=GB2HMC,=GB2HRH,=GB2IGB,=GB2IGS,=GB2IMG,=GB2IMM,=GB2INV,=GB2IOT, + =GB2JCM,=GB2KDR,=GB2KGB,=GB2KW,=GB2LBN,=GB2LBN/LH,=GB2LCL,=GB2LCP,=GB2LCT,=GB2LDG,=GB2LG,=GB2LGB, + =GB2LHI,=GB2LK,=GB2LK/LH,=GB2LMG,=GB2LP,=GB2LS,=GB2LS/LH,=GB2LSS,=GB2LT,=GB2LT/LH,=GB2LXX,=GB2M, + =GB2MAS,=GB2MBB,=GB2MDG,=GB2MN,=GB2MOF,=GB2MSL,=GB2MUC,=GB2MUL,=GB2NBC,=GB2NEF,=GB2NL,=GB2NMM, + =GB2OL,=GB2OWM,=GB2PBF,=GB2PG,=GB2QM,=GB2RB,=GB2RDR,=GB2RRL,=GB2RWW,=GB2SAA,=GB2SAM,=GB2SAS, + =GB2SB,=GB2SBG,=GB2SHL/LH,=GB2SKG,=GB2SLH,=GB2SMM,=GB2SOH,=GB2SQN,=GB2SR,=GB2SSB,=GB2SUM,=GB2SWF, + =GB2TDS,=GB2THL,=GB2TNL,=GB2VCB,=GB2VEF,=GB2WBF,=GB2WG,=GB2WLS,=GB2YLS,=GB2ZE,=GB3ANG,=GB3GKR, + =GB3LER,=GB3LER/B,=GB3ORK,=GB3ORK/B,=GB3SWF,=GB3WOI,=GB4AAS,=GB4AST,=GB4BBR,=GB4BG,=GB4CGS, + =GB4CMA,=GB4DAS,=GB4DHX,=GB4DTD,=GB4DUK,=GB4EPC,=GB4GD,=GB4GDS,=GB4GS,=GB4IE,=GB4JCM,=GB4JPJ, + =GB4JYS,=GB4LER,=GB4MSE,=GB4NFE,=GB4OL,=GB4PAS,=GB4SK,=GB4SKO,=GB4SLH,=GB4SMM,=GB4SRO,=GB4SWF, + =GB50FVS,=GB50GDS,=GB50JS,=GB50WAB,=GB5AG,=GB5AST,=GB5BBS,=GB5BOH,=GB5C,=GB5CCC,=GB5CS,=GB5DHL, + =GB5DX,=GB5EMF,=GB5FHC,=GB5FLM,=GB5JS,=GB5LTH,=GB5RO,=GB5RO/LH,=GB5RR,=GB5SI,=GB5TAM,=GB5TI, + =GB60CRB,=GB6BEN,=GB6TAA,=GB6WW,=GB75CC,=GB75GD,=GB80GD,=GB8AYR,=GB8CSL,=GB8FSG,=GB8RU,=GB8RUM, + =GB90RSGB/11,=GB90RSGB/12,=GB90RSGB/21,=GB90RSGB/22,=GB90RSGB/23,=GB999SPC,=GG100AGG,=GG100GA, + =GG100GCC,=GG100GGP,=GG100GGR,=GG100GLD,=GG100SBG,=GM/DL5SE/LH,=GM0AZC/2K,=GM0DHZ/P,=GM0GFL/P, + =GM0KTO/2K,=GM0MUN/2K,=GM0SGB/P,=GM0WUX/2K,=GM3JIJ/2K,=GM3OFT/P,=GM3TKV/LH,=GM3TTC/P,=GM3TXF/P, + =GM3USR/P,=GM3VLB/P,=GM4AFF/P,=GM4CHX/2K,=GM4CHX/P,=GM4WSB/M,=GM4WSB/P,=GM4ZVD/P,=GM6WRW/P, + =GO0AEG,=GO0AIR,=GO0BKC,=GO0DBW,=GO0DBW/M,=GO0DEQ,=GO0GMN,=GO0OGN,=GO0SYY,=GO0TUB,=GO0VRP,=GO0WEZ, + =GO1BAN,=GO1BKF,=GO1MQE,=GO1TBW,=GO2MP,=GO3HVK,=GO3JIJ,=GO3NIG,=GO3VTB,=GO4BLO,=GO4CAU,=GO4CFS, + =GO4CHX,=GO4CXM,=GO4DLG,=GO4EMX,=GO4FAM,=GO4FAU,=GO4JOJ,=GO4JPZ,=GO4JR,=GO4MOX,=GO4MSL,=GO4PRB, + =GO4UBJ,=GO4VTB,=GO4WZG,=GO4XQJ,=GO6JEP,=GO6JRX,=GO6KON,=GO6LYJ,=GO6VCV,=GO7GAX,=GO7GDE,=GO7HUD, + =GO7TUD,=GO7WEF,=GO8CBQ,=GO8MHU,=GO8SVB,=GO8TTD,=GQ0AEG,=GQ0AIR,=GQ0BKC,=GQ0BWR,=GQ0DBW,=GQ0DEQ, + =GQ0DUX,=GQ0FNE,=GQ0GMN,=GQ0HUO,=GQ0KWL,=GQ0MUN,=GQ0NTL,=GQ0OGN,=GQ0RNR,=GQ0TKV/P,=GQ0VRP,=GQ0WEZ, + =GQ0WNR,=GQ1BAN,=GQ1BKF,=GQ1MQE,=GQ1TBW,=GQ3JIJ,=GQ3JQJ,=GQ3NIG,=GQ3NTL,=GQ3TKP,=GQ3TKP/P,=GQ3TKV, + =GQ3TKV/P,=GQ3VTB,=GQ3WUX,=GQ3ZBE,=GQ4AGG,=GQ4BAE,=GQ4BLO,=GQ4CAU,=GQ4CFS,=GQ4CHX,=GQ4CHX/P, + =GQ4CXM,=GQ4DLG,=GQ4ELV,=GQ4EMX,=GQ4FAU,=GQ4JOJ,=GQ4JPZ,=GQ4JR,=GQ4MSL,=GQ4OBG,=GQ4PRB,=GQ4UIB, + =GQ4UPL,=GQ4VTB,=GQ4WZG,=GQ4XQJ,=GQ4YMM,=GQ6JEP,=GQ6JRX,=GQ6KON,=GQ6LYJ,=GQ7GAX,=GQ7GDE,=GQ7HUD, + =GQ7TUD,=GQ7UED,=GQ7WEF,=GQ8CBQ,=GQ8MHU,=GQ8PLR,=GQ8SVB,=GQ8TTD,=GR0AXY,=GR0CDV,=GR0DBW,=GR0EKM, + =GR0GMN,=GR0GRD,=GR0HPK,=GR0HPL,=GR0HUO,=GR0OGN,=GR0PNS,=GR0SYV,=GR0TTV,=GR0TUB,=GR0UKZ,=GR0VRP, + =GR0WED,=GR0WNR,=GR150NIB,=GR1BAN,=GR1MWK,=GR1TBW,=GR1ZIV,=GR3JFG,=GR3MZX,=GR3NIG,=GR3OFT,=GR3PPE, + =GR3PYU,=GR3VAL,=GR3VTB,=GR3WFJ,=GR3YXJ,=GR3ZDH,=GR4BDJ,=GR4BLO,=GR4CAU,=GR4CCN,=GR4CFS,=GR4CMI, + =GR4CXM,=GR4DLG,=GR4EMX,=GR4EOU,=GR4FQE,=GR4GIF,=GR4JOJ,=GR4NSZ,=GR4PRB,=GR4SQM,=GR4VTB,=GR4XAW, + =GR4XMD,=GR4XQJ,=GR4YMM,=GR6JEP,=GR6JNJ,=GR7AAJ,=GR7GAX,=GR7GDE,=GR7GMC,=GR7HHB,=GR7HUD,=GR7LNO, + =GR7NZI,=GR7TUD,=GR7USC,=GR7VSB,=GR8CBQ,=GR8KJO,=GR8KPH,=GR8MHU,=GR8OFQ,=GR8SVB,=GS4WAB/P,=GV0DBW, + =GV0GMN,=GV0GRD,=GV0LZE,=GV0OBX,=GV0OGN,=GV0SYV,=GV0VRP,=GV1BAN,=GV3EEW,=GV3JIJ,=GV3NHQ,=GV3NIG, + =GV3NKG,=GV3NNZ,=GV3PIP,=GV3ULP,=GV3VTB,=GV4BLO,=GV4EMX,=GV4HRJ,=GV4ILS,=GV4JOJ,=GV4KLN,=GV4LVW, + =GV4PRB,=GV4VTB,=GV4XQJ,=GV6KON,=GV7DHA,=GV7GDE,=GV7GMC,=GV8AVM,=GV8DPV,=GV8LYS,=MB18FIFA, + =MM/DH5JBR/P,=MM/DJ4OK/M,=MM/DJ8OK/M,=MM/DL5SE/LH,=MM/F5BLC/P,=MM/F5LMJ/P,=MM/HB9IAB/P, + =MM/KE5TF/P,=MM/N5ET/P,=MM/OK1FZM/P,=MM/W5ZE/P,=MM0BNN/LH,=MM0BQI/2K,=MM0BQN/2K,=MM0BYE/2K, + =MM0DFV/P,=MM0LON/M,=MM0SHF/P,=MM0YHB/P,=MM0ZOL/LH,=MM5PSL/P,=MM5YLO/P,=MO0BFF,=MO0CWJ,=MO0CYR, + =MO0DBC,=MO0DNX,=MO0FMF,=MO0GXQ,=MO0HZT,=MO0JST/P,=MO0KJG,=MO0KSS,=MO0NFC,=MO0SGQ,=MO0SJT,=MO0TGB, + =MO0TSG,=MO0WKC,=MO0XXW,=MO0ZBH,=MO1AWV,=MO1HMV,=MO3BCA,=MO3BRR,=MO3GPL,=MO3OQR,=MO3TUP,=MO3UVL, + =MO3YHA,=MO3YMU,=MO3ZRF,=MO5PSL,=MO6BJJ,=MO6CCS,=MO6CHM,=MO6CRQ,=MO6CRQ/M,=MO6DGZ,=MO6HUT,=MO6KAU, + =MO6KAU/M,=MO6KSJ,=MO6MCV,=MO6SRL,=MO6TEW,=MQ0BNN/P,=MQ0BQM,=MQ0BRG,=MQ0CIN,=MQ0CXA,=MQ0CYR, + =MQ0DNX,=MQ0DXD,=MQ0EQE,=MQ0FMF,=MQ0GXQ,=MQ0GYX,=MQ0GYX/P,=MQ0KJG,=MQ0KSS,=MQ0LEN,=MQ0NFC,=MQ0NJC, + =MQ0SJT,=MQ0TSG,=MQ0WKC,=MQ0XXW,=MQ0ZBH,=MQ1AWV,=MQ1HMV,=MQ1JWF,=MQ3BCA,=MQ3BRR,=MQ3ERZ,=MQ3FET, + =MQ3OVK,=MQ3SVK,=MQ3UIX,=MQ3UVL,=MQ3YHA,=MQ3YMU,=MQ3ZRF,=MQ5PSL,=MQ6AQM,=MQ6BJJ,=MQ6CCS,=MQ6CHM, + =MQ6CRQ,=MQ6DGZ,=MQ6HUT,=MQ6KAJ,=MQ6KAU,=MQ6KSJ,=MQ6KUA,=MQ6LMP,=MQ6MCV,=MR0BQN,=MR0CWB,=MR0CXA, + =MR0DHQ,=MR0DWF,=MR0DXD,=MR0DXH,=MR0EPC,=MR0EQE,=MR0FME,=MR0FMF,=MR0GCF,=MR0GGG,=MR0GGI,=MR0GOR, + =MR0HAI,=MR0HVU,=MR0OIL,=MR0POD,=MR0PSL,=MR0RDM,=MR0SGQ,=MR0SJT,=MR0TAI,=MR0TSG,=MR0TSS,=MR0VTV, + =MR0WEI,=MR0XAF,=MR0XXP,=MR0XXW,=MR1AWV,=MR1HMV,=MR1JWF,=MR1VTB,=MR3AWA,=MR3AWD,=MR3BRR,=MR3PTS, + =MR3UIX,=MR3UVL,=MR3WJZ,=MR3XGP,=MR3YHA,=MR3YPH,=MR3ZCS,=MR5PSL,=MR6AHB,=MR6ARN,=MR6ATU,=MR6CHM, + =MR6CTH,=MR6CTL,=MR6HFC,=MR6MCV,=MR6RLL,=MR6SSI,=MR6TMS,=MV0DXH,=MV0FME,=MV0FMF,=MV0GHM,=MV0HAR, + =MV0LGS,=MV0NFC,=MV0NJS,=MV0SGQ,=MV0SJT,=MV0XXW,=MV1VTB,=MV3BRR,=MV3CVB,=MV3YHA,=MV3YMU,=MV5PSL, + =MV6BJJ,=MV6KSJ,=MV6NRQ; Guernsey: 14: 27: EU: 49.45: 2.58: 0.0: GU: 2U,GP,GU,MP,MU,=2O0FER,=2Q0ARE,=2Q0FER,=2U0ARE/2K,=GB0HAM,=GB0U,=GB19CG,=GB2AFG,=GB2FG,=GB2GU, =GB2JTA,=GB4SGG,=GB50GSY,=GO8FBO,=GQ8FBO,=GU0DXX/2K,=GU4GG/2K,=MO0FAL,=MO0KWD,=MQ0FAL,=MR0FAL, @@ -942,65 +951,66 @@ Wales: 14: 27: EU: 52.28: 3.73: 0.0: GW: =2Q0DAA/M,=2Q0IDT,=2Q0MKG,=2Q0OJA,=2Q0OTL,=2Q0RMR,=2Q0RWF,=2Q0SVW,=2Q0TRR,=2Q0UAA,=2Q0VAY,=2Q0WDS, =2R0BRR,=2R0CDY,=2R0CDZ,=2R0CSS,=2R0CVE,=2R0DRB,=2R0IDT,=2R0OJA,=2R0PHP,=2R0PJP,=2R0REX,=2R0RWF, =2R0TRR,=2R0TYG,=2R0XTP,=2R0YKK,=2R3SFC,=2V0CDY,=2V0CGM,=2V0CLJ,=2V0CVL,=2V0DAA,=2V0DUN,=2V0GME, - =2V0GNG,=2V0KED,=2V0WDS,=2V1EPO,=GB0AAW,=GB0AD,=GB0AWE,=GB0AWS,=GB0BHR,=GB0BP,=GB0BRE,=GB0BTB, - =GB0BVL,=GB0BYL,=GB0CCE,=GB0CEW,=GB0CFD,=GB0CGG,=GB0CLC,=GB0CQD,=GB0CSA,=GB0CSR,=GB0CVA,=GB0DFD, - =GB0DMT,=GB0DS,=GB0DVP,=GB0FHD,=GB0FHI,=GB0GDD,=GB0GIW,=GB0GLV,=GB0GMD,=GB0GRM,=GB0HEL,=GB0HGC, - =GB0HLT,=GB0HMM,=GB0HMT,=GB0KF,=GB0L,=GB0LBG,=GB0LM,=GB0LVF,=GB0MFH,=GB0MIW,=GB0ML,=GB0MPA, - =GB0MUU,=GB0MWL,=GB0NAW,=GB0NEW,=GB0NG,=GB0NLC,=GB0PBR,=GB0PEM,=GB0PGG,=GB0PLB,=GB0PLL,=GB0PSG, - =GB0RME,=GB0ROC,=GB0RPO,=GB0RS,=GB0RSC,=GB0RSF,=GB0RWM,=GB0SDD,=GB0SGC,=GB0SH,=GB0SH/LH,=GB0SOA, - =GB0SPE,=GB0SPS,=GB0TD,=GB0TPR,=GB0TS,=GB0TTT,=GB0VCA,=GB0VK,=GB0WHH,=GB0WHR,=GB0WIW,=GB0WUL, - =GB0YG,=GB100AB,=GB100BP,=GB100CSW,=GB100GGC,=GB100GGM,=GB100HD,=GB100LB,=GB100LSG,=GB100MCV, - =GB100TMD,=GB10SOTA,=GB19CGW,=GB19CW,=GB19SG,=GB1AD,=GB1ATC,=GB1BAF,=GB1BGS,=GB1BPL,=GB1BSW, - =GB1BW,=GB1CCC,=GB1CDS,=GB1CPG,=GB1DS,=GB1FHS,=GB1HAS,=GB1HTW,=GB1JC,=GB1LSG,=GB1LW,=GB1OOC, - =GB1PCA,=GB1PCS,=GB1PD,=GB1PGW,=GB1PJ,=GB1PLL,=GB1SEA,=GB1SL,=GB1SPN,=GB1SSL,=GB1TDS,=GB1WAA, - =GB1WIW,=GB1WSM,=GB2000SET,=GB2003SET,=GB200HNT,=GB250TMB,=GB250TT,=GB2ADU,=GB2BEF,=GB2BGG, - =GB2BOM,=GB2BOW,=GB2BPM,=GB2BYF,=GB2CC,=GB2CI,=GB2COB,=GB2CR,=GB2CRS,=GB2DWR,=GB2EI,=GB2FC, - =GB2FLB,=GB2GGM,=GB2GLS,=GB2GOL,=GB2GSG,=GB2GVA,=GB2HDG,=GB2IMD,=GB2LBR,=GB2LM,=GB2LNP,=GB2LSA, - =GB2LSA/LH,=GB2LSH,=GB2MD,=GB2MGY,=GB2MIL,=GB2MMC,=GB2MOP,=GB2NF,=GB2NPH,=GB2NPL,=GB2OOA,=GB2PRC, - =GB2RFS,=GB2RTB,=GB2SAC,=GB2SCD,=GB2SCP,=GB2SFM,=GB2SIP,=GB2SLA,=GB2TD,=GB2TD/LH,=GB2TTA,=GB2VK, - =GB2WAA,=GB2WHO,=GB2WNA,=GB2WSF,=GB2WT,=GB3HLS,=GB3LMW,=GB4ADU,=GB4AFS,=GB4AOS,=GB4BB,=GB4BOJ, - =GB4BPL,=GB4BPL/LH,=GB4BPL/P,=GB4BPR,=GB4BRS/P,=GB4BSG,=GB4CI,=GB4CTC,=GB4EUL,=GB4FAA,=GB4GM, - =GB4GSS,=GB4HFH,=GB4HI,=GB4HLB,=GB4HMD,=GB4HMM,=GB4MBC,=GB4MD,=GB4MDH,=GB4MDI,=GB4MJS,=GB4MPI, - =GB4MUU,=GB4NDG,=GB4NPL,=GB4NTB,=GB4ON,=GB4OST,=GB4PAT,=GB4PCS,=GB4PD,=GB4POW,=GB4RC,=GB4RME, - =GB4RSL,=GB4SDD,=GB4SLC,=GB4SSP,=GB4SUB,=GB4TMS,=GB4UKG,=GB4VJD,=GB4WT,=GB4WWI,=GB4XT,=GB50ABS, - =GB50EVS,=GB50RSC,=GB50SGP,=GB5AC,=GB5FI,=GB5GEO,=GB5IMD,=GB5MD,=GB5ONG,=GB5PSJ,=GB5SIP,=GB5WT, - =GB60DITP,=GB60ER,=GB60PW,=GB60SPS,=GB60VLY,=GB65BTF,=GB6AC,=GB6BLB,=GB6CRI,=GB6GGM,=GB6OQA, - =GB6ORA,=GB6PLB,=GB6RNLI,=GB6SPD,=GB6TS,=GB6TSG,=GB6WT,=GB6WWT,=GB70BTF,=GB750CC,=GB75ATC,=GB75BB, - =GB8CCC,=GB8HI,=GB8MD,=GB8MG,=GB8OAE,=GB8OQE,=GB8RAF,=GB8WOW,=GB8WT,=GB90RSGB/62,=GB90RSGB/72, - =GB9GGM,=GC4BRS/LH,=GG100ACD,=GG100ANG,=GG100CPG,=GG100RGG,=GG100SG,=GO0DIV,=GO0EZQ,=GO0EZY, - =GO0JEQ,=GO0MNP,=GO0MNP/P,=GO0NPL,=GO0PLB,=GO0PNI,=GO0PUP,=GO0VKW,=GO0VML,=GO0VSW,=GO1DPL,=GO1IOT, - =GO1JFV,=GO1MVL,=GO1PKM,=GO3PLB,=GO3UOF,=GO3UOF/M,=GO3XJQ,=GO4BKG,=GO4BLE,=GO4CQZ,=GO4DTQ,=GO4GTI, - =GO4JKR,=GO4JUN,=GO4JUW,=GO4MVA,=GO4NOO,=GO4OKT,=GO4SUE,=GO4SUE/P,=GO4TNZ,=GO4WXM,=GO6IMS,=GO6NKG, - =GO6UKO,=GO7DWR,=GO7SBO,=GO7VJK,=GO7VQD,=GO8BQK,=GO8IQC,=GO8JOY,=GO8OKR,=GQ0ANA,=GQ0DIV,=GQ0JEQ, - =GQ0JRF,=GQ0MNO,=GQ0MNP,=GQ0NPL,=GQ0PUP,=GQ0RYT,=GQ0SLM,=GQ0TQM,=GQ0VKW,=GQ0VML,=GQ0VSW,=GQ0WVL, - =GQ1FKY,=GQ1FOA/P,=GQ1IOT,=GQ1JFV,=GQ1MVL,=GQ1NRS,=GQ1WRV,=GQ1ZKN,=GQ3IRK,=GQ3PLB,=GQ3SB,=GQ3UOF, - =GQ3VEN,=GQ3VKL,=GQ3WSU,=GQ3XJA,=GQ3XJQ,=GQ4BKG,=GQ4BLE,=GQ4CQZ,=GQ4EZW,=GQ4GSH,=GQ4GTI,=GQ4IIL, - =GQ4JKR,=GQ4JUN,=GQ4JUW,=GQ4LZP,=GQ4MVA,=GQ4NOO,=GQ4OKT,=GQ4SUE,=GQ4VNS,=GQ4VZJ,=GQ4WXM,=GQ4WXM/P, - =GQ6IMS,=GQ6ITJ,=GQ6NKG,=GQ6UKO,=GQ7BQK,=GQ7DWR,=GQ7FBV,=GQ7SBO,=GQ7UNJ,=GQ7UNV,=GQ7VJK,=GQ7VQD, - =GQ8BQK,=GQ8IQC,=GQ8JOY,=GQ8OKR,=GR0ANA,=GR0DIV,=GR0DSP,=GR0HUS,=GR0JEQ,=GR0MYY,=GR0NPL,=GR0PSV, - =GR0RYT,=GR0SYN,=GR0TKX,=GR0VKW,=GR0WGK,=GR1FJI,=GR1HNG,=GR1LFX,=GR1LHV,=GR1MCD,=GR1SGG,=GR1WVY, - =GR1YQM,=GR3SB,=GR3SFC,=GR3TKH,=GR3UOF,=GR3XJQ,=GR4BKG,=GR4BLE,=GR4CQZ,=GR4GNY,=GR4GTI,=GR4HZA, - =GR4JUN,=GR4JUW,=GR4OGO,=GR4SUE,=GR4VSS/P,=GR4XXJ,=GR4ZOM,=GR5PH,=GR6NKG,=GR6SIX,=GR6STK,=GR6UKO, - =GR6ZDH,=GR7AAV,=GR7HOC,=GR7NAU,=GR7TKZ,=GR7UNV,=GR7VQD,=GR8BQK,=GR8IQC,=GR8OGI,=GR8TRO,=GV0ANA, - =GV0DCK,=GV0DIV,=GV0EME,=GV0FRE,=GV0MNP,=GV0NPL,=GV1FKY,=GV1IOT,=GV1JFV,=GV1NBW,=GV1YQM,=GV3ATZ, - =GV3TJE/P,=GV3UOF,=GV3WEZ,=GV3XJQ,=GV4BKG,=GV4BRS,=GV4CQZ,=GV4JKR,=GV4JQP,=GV4NQJ,=GV4PUC,=GV6BRC, - =GV6JPC,=GV6NKG,=GV7UNV,=GV7VJK,=GV8IQC,=GW0AWT/2K,=GW0GEI/2K,=GW0GIH/2K,=GW0MNO/2K,=GW0VSW/2K, - =GW3JXN/2K,=GW3KJN/2K,=GW4IIL/2K,=GW4VHP/2K,=M2000Y/97A,=MO0AQZ,=MO0ATI,=MO0COE,=MO0CVT,=MO0EQL, - =MO0EZQ,=MO0GXE,=MO0HCX,=MO0IBZ,=MO0IML,=MO0KLW,=MO0LDJ,=MO0LLK,=MO0LUK,=MO0LZZ,=MO0MAU,=MO0MUM, - =MO0MWZ,=MO0OWW,=MO0SGD,=MO0SGR,=MO0TBB,=MO0TMI,=MO0TTU,=MO0UPH,=MO0VVO,=MO1CFA,=MO1CFN,=MO3DAO, - =MO3DQB,=MO3GKI,=MO3OJA,=MO3PUU,=MO3RNI,=MO3UEZ,=MO3WPH,=MO3YVO,=MO3ZCO,=MO6DVP,=MO6GWK,=MO6GWR, - =MO6GWR/P,=MO6MAU,=MO6PAM,=MO6PLC,=MO6PUT,=MO6SEF,=MO6TBD,=MO6TBP,=MO6WLB,=MQ0AQZ,=MQ0ATI,=MQ0AWW, - =MQ0CDO,=MQ0CNA,=MQ0CVT,=MQ0DHF,=MQ0EQL,=MQ0GXE,=MQ0GYV,=MQ0HCX,=MQ0IBZ,=MQ0IML,=MQ0LDJ,=MQ0LLK, - =MQ0LUK,=MQ0LZZ,=MQ0MAU,=MQ0MUM,=MQ0MWA,=MQ0MWZ,=MQ0OWW,=MQ0PAD,=MQ0RHD,=MQ0SGD,=MQ0SGR,=MQ0TBB, - =MQ0TMI,=MQ0TTU,=MQ0UPH,=MQ0UPH/P,=MQ0VVO,=MQ0XMC/P,=MQ1CFA,=MQ1CFN,=MQ1EYO/P,=MQ1LCR,=MQ3DAO, - =MQ3EPA,=MQ3GKI,=MQ3JAT,=MQ3NDB,=MQ3OJA,=MQ3USK,=MQ3WPH,=MQ3ZCB/P,=MQ5AND,=MQ5EPA,=MQ5VZW,=MQ6DVP, - =MQ6KLL,=MQ6MAU,=MQ6PAM,=MQ6PLC,=MQ6RHD,=MQ6SEF,=MQ6TBD,=MQ6TBP,=MR0AQZ,=MR0BXJ,=MR0CVT,=MR0GUK, - =MR0GXE,=MR0IDX,=MR0JGE,=MR0LAO,=MR0LDJ,=MR0MAU,=MR0RLD,=MR0TTR,=MR0TTU,=MR0YAD,=MR0ZAP,=MR1CFN, - =MR1EAA,=MR1LCR,=MR1MAJ/P,=MR1MDH,=MR3AVB,=MR3AVC,=MR3CBF,=MR3NYR,=MR3OBL,=MR3SET/P,=MR3UFN, - =MR3XZP,=MR3YKL,=MR3YLO,=MR3YVO,=MR3ZCB/P,=MR5HOC,=MR6ADZ,=MR6KDA,=MR6VHF,=MR6YDP,=MV0AEL,=MV0BLM, - =MV0EDX,=MV0GWT,=MV0GXE,=MV0HGY/P,=MV0IML,=MV0LLK,=MV0PJJ,=MV0PJJ/P,=MV0RRD,=MV0SGD,=MV0SGR, - =MV0TBB,=MV0TDQ,=MV0UAA,=MV0USK,=MV0VRQ,=MV0WYN,=MV1CFA,=MV1CFN,=MV1EYP/P,=MV3RNI,=MV6CQN,=MV6GWR, - =MV6GWR/P,=MV6URC,=MV6ZOL,=MW0CND/2K,=MW0DHF/LH,=MW5AAM/2K,=MW5GOL/LH; + =2V0GNG,=2V0KED,=2V0WDS,=2V1EPO,=GB0AAW,=GB0AD,=GB0ATM,=GB0AWE,=GB0AWS,=GB0BHR,=GB0BP,=GB0BRE, + =GB0BTB,=GB0BVL,=GB0BYL,=GB0CAC,=GB0CCE,=GB0CEW,=GB0CFD,=GB0CGG,=GB0CLC,=GB0CQD,=GB0CSA,=GB0CSR, + =GB0CVA,=GB0DFD,=GB0DMT,=GB0DS,=GB0DVP,=GB0FHD,=GB0FHI,=GB0GDD,=GB0GIW,=GB0GLV,=GB0GMD,=GB0GRM, + =GB0HEL,=GB0HGC,=GB0HLT,=GB0HMM,=GB0HMT,=GB0KF,=GB0L,=GB0LBG,=GB0LM,=GB0LVF,=GB0MFH,=GB0MIW, + =GB0ML,=GB0MPA,=GB0MUU,=GB0MWL,=GB0NAW,=GB0NEW,=GB0NG,=GB0NLC,=GB0PBR,=GB0PEM,=GB0PGG,=GB0PLB, + =GB0PLL,=GB0PSG,=GB0RME,=GB0ROC,=GB0RPO,=GB0RS,=GB0RSC,=GB0RSF,=GB0RWM,=GB0SDD,=GB0SGC,=GB0SH, + =GB0SH/LH,=GB0SOA,=GB0SPE,=GB0SPS,=GB0TD,=GB0TPR,=GB0TS,=GB0TTT,=GB0VCA,=GB0VK,=GB0WHH,=GB0WHR, + =GB0WIW,=GB0WUL,=GB0YG,=GB100AB,=GB100BP,=GB100CSW,=GB100GGC,=GB100GGM,=GB100HD,=GB100LB, + =GB100LSG,=GB100MCV,=GB100TMD,=GB10SOTA,=GB19CGW,=GB19CW,=GB19SG,=GB1AD,=GB1ATC,=GB1BAF,=GB1BGS, + =GB1BPL,=GB1BSW,=GB1BW,=GB1CCC,=GB1CDS,=GB1CPG,=GB1DS,=GB1FHS,=GB1HAS,=GB1HTW,=GB1JC,=GB1LSG, + =GB1LW,=GB1OOC,=GB1PCA,=GB1PCS,=GB1PD,=GB1PGW,=GB1PJ,=GB1PLL,=GB1SEA,=GB1SL,=GB1SPN,=GB1SSL, + =GB1TDS,=GB1WAA,=GB1WIW,=GB1WSM,=GB2000SET,=GB2003SET,=GB200HNT,=GB250TMB,=GB250TT,=GB2ADU, + =GB2BEF,=GB2BGG,=GB2BOM,=GB2BOW,=GB2BPM,=GB2BYF,=GB2CC,=GB2CI,=GB2COB,=GB2CR,=GB2CRS,=GB2DWR, + =GB2EI,=GB2FC,=GB2FLB,=GB2GGM,=GB2GLS,=GB2GOL,=GB2GSG,=GB2GVA,=GB2HDG,=GB2HMM,=GB2IMD,=GB2LBR, + =GB2LM,=GB2LNP,=GB2LSA,=GB2LSA/LH,=GB2LSH,=GB2MD,=GB2MGY,=GB2MIL,=GB2MLM,=GB2MMC,=GB2MOP,=GB2NF, + =GB2NPH,=GB2NPL,=GB2OOA,=GB2ORM,=GB2PRC,=GB2RFS,=GB2RTB,=GB2SAC,=GB2SCD,=GB2SCP,=GB2SFM,=GB2SIP, + =GB2SLA,=GB2TD,=GB2TD/LH,=GB2TTA,=GB2VK,=GB2WAA,=GB2WHO,=GB2WNA,=GB2WSF,=GB2WT,=GB3HLS,=GB3LMW, + =GB4ADU,=GB4AFS,=GB4AOS,=GB4BB,=GB4BOJ,=GB4BPL,=GB4BPL/LH,=GB4BPL/P,=GB4BPR,=GB4BRS/P,=GB4BSG, + =GB4CI,=GB4CTC,=GB4EUL,=GB4FAA,=GB4GM,=GB4GSS,=GB4HFH,=GB4HI,=GB4HLB,=GB4HMD,=GB4HMM,=GB4MBC, + =GB4MD,=GB4MDH,=GB4MDI,=GB4MJS,=GB4MPI,=GB4MUU,=GB4NDG,=GB4NPL,=GB4NTB,=GB4ON,=GB4OST,=GB4PAT, + =GB4PCS,=GB4PD,=GB4POW,=GB4RC,=GB4RME,=GB4RSL,=GB4SDD,=GB4SLC,=GB4SSP,=GB4SUB,=GB4TMS,=GB4UKG, + =GB4VJD,=GB4WT,=GB4WWI,=GB4XT,=GB50ABS,=GB50EVS,=GB50RSC,=GB50SGP,=GB5AC,=GB5FI,=GB5GEO,=GB5IMD, + =GB5MD,=GB5ONG,=GB5PSJ,=GB5SIP,=GB5WT,=GB60DITP,=GB60ER,=GB60PW,=GB60SPS,=GB60VLY,=GB65BTF,=GB6AC, + =GB6BLB,=GB6CRI,=GB6GGM,=GB6OQA,=GB6ORA,=GB6PLB,=GB6RNLI,=GB6SPD,=GB6TS,=GB6TSG,=GB6WT,=GB6WWT, + =GB70BTF,=GB750CC,=GB75ATC,=GB75BB,=GB8CCC,=GB8HI,=GB8MD,=GB8MG,=GB8ND,=GB8OAE,=GB8OQE,=GB8RAF, + =GB8WOW,=GB8WT,=GB90RSGB/62,=GB90RSGB/72,=GB9GGM,=GC4BRS/LH,=GG100ACD,=GG100ANG,=GG100CPG, + =GG100RGG,=GG100SG,=GO0DIV,=GO0EZQ,=GO0EZY,=GO0JEQ,=GO0MNP,=GO0MNP/P,=GO0NPL,=GO0PLB,=GO0PNI, + =GO0PUP,=GO0VKW,=GO0VML,=GO0VSW,=GO1DPL,=GO1IOT,=GO1JFV,=GO1MVL,=GO1PKM,=GO3PLB,=GO3UOF,=GO3UOF/M, + =GO3XJQ,=GO4BKG,=GO4BLE,=GO4CQZ,=GO4DTQ,=GO4GTI,=GO4JKR,=GO4JUN,=GO4JUW,=GO4MVA,=GO4NOO,=GO4OKT, + =GO4SUE,=GO4SUE/P,=GO4TNZ,=GO4WXM,=GO6IMS,=GO6NKG,=GO6UKO,=GO7DWR,=GO7SBO,=GO7VJK,=GO7VQD,=GO8BQK, + =GO8IQC,=GO8JOY,=GO8OKR,=GQ0ANA,=GQ0DIV,=GQ0JEQ,=GQ0JRF,=GQ0MNO,=GQ0MNP,=GQ0NPL,=GQ0PUP,=GQ0RYT, + =GQ0SLM,=GQ0TQM,=GQ0VKW,=GQ0VML,=GQ0VSW,=GQ0WVL,=GQ1FKY,=GQ1FOA/P,=GQ1IOT,=GQ1JFV,=GQ1MVL,=GQ1NRS, + =GQ1WRV,=GQ1ZKN,=GQ3IRK,=GQ3PLB,=GQ3SB,=GQ3UOF,=GQ3VEN,=GQ3VKL,=GQ3WSU,=GQ3XJA,=GQ3XJQ,=GQ4BKG, + =GQ4BLE,=GQ4CQZ,=GQ4EZW,=GQ4GSH,=GQ4GTI,=GQ4IIL,=GQ4JKR,=GQ4JUN,=GQ4JUW,=GQ4LZP,=GQ4MVA,=GQ4NOO, + =GQ4OKT,=GQ4SUE,=GQ4VNS,=GQ4VZJ,=GQ4WXM,=GQ4WXM/P,=GQ6IMS,=GQ6ITJ,=GQ6NKG,=GQ6UKO,=GQ7BQK,=GQ7DWR, + =GQ7FBV,=GQ7SBO,=GQ7UNJ,=GQ7UNV,=GQ7VJK,=GQ7VQD,=GQ8BQK,=GQ8IQC,=GQ8JOY,=GQ8OKR,=GR0ANA,=GR0DIV, + =GR0DSP,=GR0HUS,=GR0JEQ,=GR0MYY,=GR0NPL,=GR0PSV,=GR0RYT,=GR0SYN,=GR0TKX,=GR0VKW,=GR0WGK,=GR1FJI, + =GR1HNG,=GR1LFX,=GR1LHV,=GR1MCD,=GR1SGG,=GR1WVY,=GR1YQM,=GR3SB,=GR3SFC,=GR3TKH,=GR3UOF,=GR3XJQ, + =GR4BKG,=GR4BLE,=GR4CQZ,=GR4GNY,=GR4GTI,=GR4HZA,=GR4JUN,=GR4JUW,=GR4OGO,=GR4SUE,=GR4VSS/P,=GR4XXJ, + =GR4ZOM,=GR5PH,=GR6NKG,=GR6SIX,=GR6STK,=GR6UKO,=GR6ZDH,=GR7AAV,=GR7HOC,=GR7NAU,=GR7TKZ,=GR7UNV, + =GR7VQD,=GR8BQK,=GR8IQC,=GR8OGI,=GR8TRO,=GV0ANA,=GV0DCK,=GV0DIV,=GV0EME,=GV0FRE,=GV0MNP,=GV0NPL, + =GV1FKY,=GV1IOT,=GV1JFV,=GV1NBW,=GV1YQM,=GV3ATZ,=GV3TJE/P,=GV3UOF,=GV3WEZ,=GV3XJQ,=GV4BKG,=GV4BRS, + =GV4CQZ,=GV4JKR,=GV4JQP,=GV4NQJ,=GV4PUC,=GV6BRC,=GV6JPC,=GV6NKG,=GV7UNV,=GV7VJK,=GV8IQC, + =GW0AWT/2K,=GW0GEI/2K,=GW0GIH/2K,=GW0MNO/2K,=GW0VSW/2K,=GW3JXN/2K,=GW3KJN/2K,=GW4IIL/2K, + =GW4VHP/2K,=M2000Y/97A,=MO0AQZ,=MO0ATI,=MO0COE,=MO0CVT,=MO0EQL,=MO0EZQ,=MO0GXE,=MO0HCX,=MO0IBZ, + =MO0IML,=MO0KLW,=MO0LDJ,=MO0LLK,=MO0LUK,=MO0LZZ,=MO0MAU,=MO0MUM,=MO0MWZ,=MO0OWW,=MO0SGD,=MO0SGR, + =MO0TBB,=MO0TMI,=MO0TTU,=MO0UPH,=MO0VVO,=MO1CFA,=MO1CFN,=MO3DAO,=MO3DQB,=MO3GKI,=MO3OJA,=MO3PUU, + =MO3RNI,=MO3UEZ,=MO3WPH,=MO3YVO,=MO3ZCO,=MO6DVP,=MO6GWK,=MO6GWR,=MO6GWR/P,=MO6MAU,=MO6PAM,=MO6PLC, + =MO6PUT,=MO6SEF,=MO6TBD,=MO6TBP,=MO6WLB,=MQ0AQZ,=MQ0ATI,=MQ0AWW,=MQ0CDO,=MQ0CNA,=MQ0CVT,=MQ0DHF, + =MQ0EQL,=MQ0GXE,=MQ0GYV,=MQ0HCX,=MQ0IBZ,=MQ0IML,=MQ0LDJ,=MQ0LLK,=MQ0LUK,=MQ0LZZ,=MQ0MAU,=MQ0MUM, + =MQ0MWA,=MQ0MWZ,=MQ0OWW,=MQ0PAD,=MQ0RHD,=MQ0SGD,=MQ0SGR,=MQ0TBB,=MQ0TMI,=MQ0TTU,=MQ0UPH,=MQ0UPH/P, + =MQ0VVO,=MQ0XMC/P,=MQ1CFA,=MQ1CFN,=MQ1EYO/P,=MQ1LCR,=MQ3DAO,=MQ3EPA,=MQ3GKI,=MQ3JAT,=MQ3NDB, + =MQ3OJA,=MQ3USK,=MQ3WPH,=MQ3ZCB/P,=MQ5AND,=MQ5EPA,=MQ5VZW,=MQ6DVP,=MQ6KLL,=MQ6MAU,=MQ6PAM,=MQ6PLC, + =MQ6RHD,=MQ6SEF,=MQ6TBD,=MQ6TBP,=MR0AQZ,=MR0BXJ,=MR0CVT,=MR0GUK,=MR0GXE,=MR0IDX,=MR0JGE,=MR0LAO, + =MR0LDJ,=MR0MAU,=MR0RLD,=MR0TTR,=MR0TTU,=MR0YAD,=MR0ZAP,=MR1CFN,=MR1EAA,=MR1LCR,=MR1MAJ/P,=MR1MDH, + =MR3AVB,=MR3AVC,=MR3CBF,=MR3NYR,=MR3OBL,=MR3SET/P,=MR3UFN,=MR3XZP,=MR3YKL,=MR3YLO,=MR3YVO, + =MR3ZCB/P,=MR5HOC,=MR6ADZ,=MR6KDA,=MR6VHF,=MR6YDP,=MV0AEL,=MV0BLM,=MV0EDX,=MV0GWT,=MV0GXE, + =MV0HGY/P,=MV0IML,=MV0LLK,=MV0PJJ,=MV0PJJ/P,=MV0RRD,=MV0SGD,=MV0SGR,=MV0TBB,=MV0TDQ,=MV0UAA, + =MV0USK,=MV0VRQ,=MV0WYN,=MV1CFA,=MV1CFN,=MV1EYP/P,=MV3RNI,=MV6CQN,=MV6GWR,=MV6GWR/P,=MV6URC, + =MV6ZOL,=MW0CND/2K,=MW0DHF/LH,=MW5AAM/2K,=MW5GOL/LH; Solomon Islands: 28: 51: OC: -9.00: -160.00: -11.0: H4: H4,=H40/H44RK; Temotu Province: 32: 51: OC: -10.72: -165.80: -11.0: H40: @@ -1052,10 +1062,10 @@ Saudi Arabia: 21: 39: AS: 24.20: -43.83: -3.0: HZ: =HZ1SK/ND,=HZ1TL/ND,=HZ1TT/ND,=HZ1XB/ND,=HZ1ZH/ND; Italy: 15: 28: EU: 42.82: -12.58: -1.0: I: I,=II0PN/MM(40),=II1RT/N,=IO9HQ,=IP1T/LH, - =4U0WFP,=4U4F,=4U5F,=4U6F,=4U7F,=4U7FOC,=4U80FOC,=4U8F,=4U8FOC,=IK0ATK/N,=IK0CNA/LH,=IK0JFS/N, - =IK0XFD/N,=IQ0AP/J,=IQ0CV/LH,=IQ0FM/LH,=IQ0FR/LH,=IQ0GV/AAW,=IR0BP/J,=IU0FSC/LH,=IW0HP/N, - =IW9GSH/0,=IZ0BXZ/N,=IZ0DBA/N,=IZ0EGC/N,=IZ0FVD/N,=IZ0HTW/PS,=IZ0HTW/SP,=IZ0IAT/LH,=IZ0IJC/FF, - =IZ0IJC/N, + =4U0WFP,=4U4F,=4U5F,=4U6F,=4U7F,=4U7FOC,=4U80FOC,=4U8F,=4U8FOC,=II0IDR/NAVY,=IK0ATK/N,=IK0CNA/LH, + =IK0JFS/N,=IK0XFD/N,=IQ0AP/J,=IQ0CV/LH,=IQ0FM/LH,=IQ0FR/LH,=IQ0GV/AAW,=IR0BP/J,=IU0FSC/LH, + =IW0HP/N,=IW9GSH/0,=IZ0BXZ/N,=IZ0DBA/N,=IZ0EGC/N,=IZ0FVD/N,=IZ0HTW/PS,=IZ0HTW/SP,=IZ0IAT/LH, + =IZ0IJC/FF,=IZ0IJC/N, =I1MQ/N,=I1ULJ/N,=I1XSG/N,=I1YRL/GRA,=II1PV/LH,=IK1RED/N,=IK1VDN/N,=IQ1L/LH,=IQ1NM/REX,=IQ1SP/N, =IY1SP/ASB,=IY1SP/MTN,=IZ0IJC/BSM,=IZ1CLA/N,=IZ1FCF/N,=IZ1POA/N,=IZ1RGI/ECO,=IZ5GST/1/LH, =I2AZ/CA,=I2AZ/N,=I2CZQ/N,=IK2CZQ/N,=IK2FIQ/N,=IK2MKM/EXPO,=IK2SOE/CA,=IK2SOE/N,=IQ2LB/EXPO, @@ -1069,10 +1079,10 @@ Italy: 15: 28: EU: 42.82: -12.58: -1.0: I: =IQ6PS/LH,=IQ6SB/LGH,=IQ6SB/LGT,=IQ6SB/LH,=IQ6VP/J,=IZ6ASI/LH,=IZ6ASI/N,=IZ6CDI/O,=IZ6RWD/O, =IZ6TGS/LH,=IZ6TGS/N, =4U13FEB,=4U1GSC,=4U20B,=4U24OCT,=4U29MAY,=4U73B,=I7PXV/LH,=I7PXV/P/LH,=I7XUW/MI/224,=II7IAOI/N, - =II7PT/C,=II7PT/D,=II7PT/E,=II7PT/F,=II7PT/G,=II7PT/H,=II7PT/L,=IK7JWX/LH,=IQ7ML/J,=IQ7ML/LH, - =IQ7QK/LH,=IU7SCT/J,=IZ2DPX/7/LH,=IZ7DKA/YL,=IZ7KDX/LH,=IZ7LDC/LH, - =IK2RLS/8/LH,=IK8TEO/N,=IQ8OM/N,=IQ8PC/BWL,=IQ8XS/CEU,=IW8FFG/J,=IZ8AJQ/LGT,=IZ8AJQ/LH, - =IZ8DBJ/LGT,=IZ8DBJ/LH,=IZ8FMU/KR,=IZ8IZK/YL,=IZ8JPV/N,=IZ8QNX/N, + =II7PT/C,=II7PT/D,=II7PT/E,=II7PT/F,=II7PT/G,=II7PT/H,=II7PT/L,=II8ICN/NAVY,=IK7JWX/LH,=IK7SHC/MT, + =IQ7ML/J,=IQ7ML/LH,=IQ7QK/LH,=IU7SCT/J,=IZ2DPX/7/LH,=IZ7DKA/YL,=IZ7KDX/LH,=IZ7LDC/LH, + =IK2RLS/8/LH,=IK8IJN/I/US,=IK8TEO/N,=IQ8OM/N,=IQ8PC/BWL,=IQ8XS/CEU,=IU8CEU/8CZ,=IW8FFG/J, + =IZ8AJQ/LGT,=IZ8AJQ/LH,=IZ8DBJ/LGT,=IZ8DBJ/LH,=IZ8FMU/KR,=IZ8IZK/YL,=IZ8JPV/N,=IZ8QNX/N, =IA5/IW3ILP/L, =IC8/DJ5AA/LH, =IN3IKF/J,=IN3TJK/YL, @@ -1081,15 +1091,15 @@ African Italy: 33: 37: AF: 35.67: -12.67: -1.0: *IG9: IG9,IH9,=IO9Y,=IY9A; Sardinia: 15: 28: EU: 40.15: -9.27: -1.0: IS: IM0,IS,IW0U,IW0V,IW0W,IW0X,IW0Y,IW0Z,=II0C,=II0EUDX,=II0FDR,=II0IAML,=II0ICH,=II0IDP,=II0M,=II0P, - =II0PAX,=II0RSB,=II0SB,=II0SB/MM,=II0SRT/P,=II3EUDX,=IQ0AG,=IQ0AG/P,=IQ0AH,=IQ0AH/P,=IQ0AI, - =IQ0AI/P,=IQ0AK,=IQ0AK/P,=IQ0AL,=IQ0AL/P,=IQ0AM,=IQ0AM/P,=IQ0EH,=IQ0EH/P,=IQ0HO,=IQ0ID,=IQ0ID/P, - =IQ0NU,=IQ0NU/P,=IQ0NV,=IQ0NV/P,=IQ0OG,=IQ0OH,=IQ0QP,=IQ0QP/LH,=IQ0QP/P,=IQ0QP/WW,=IQ0SS,=IQ0SS/P, + =II0PAX,=II0RSB,=II0SB,=II0SB/MM,=II0SRE,=II0SRT/P,=II3EUDX,=IQ0AG,=IQ0AG/P,=IQ0AH,=IQ0AH/P, + =IQ0AI,=IQ0AI/P,=IQ0AK,=IQ0AK/P,=IQ0AL,=IQ0AL/P,=IQ0AM,=IQ0AM/P,=IQ0EH,=IQ0EH/P,=IQ0HO,=IQ0ID, + =IQ0ID/P,=IQ0NU,=IQ0NU/P,=IQ0NV,=IQ0NV/P,=IQ0OG,=IQ0OH,=IQ0QP,=IQ0QP/LH,=IQ0QP/P,=IQ0SS,=IQ0SS/P, =IQ0US,=IQ0UT,=IQ0XP,=IR0EO,=IR0FOC,=IR0IDP,=IR0IDP/1,=IR0IDP/2,=IR0IDP/3,=IR0LVC,=IR0MDC, - =IS0/4Z5KJ/LH,=IS0ICE/N,=IS0IGV/N,=IS0PGF/N,=IS0SDX/N,=IW0HRI,=IY0GA; + =IS0/4Z5KJ/LH,=IS0/DL5SE/LH,=IS0ICE/N,=IS0IGV/N,=IS0PGF/N,=IS0SDX/N,=IW0HRI,=IY0GA,=IY0NV; Sicily: 15: 28: EU: 37.50: -14.00: -1.0: *IT9: - IB9,ID9,IE9,IF9,II9,IJ9,IO9,IQ9,IR9,IT9,IU9,IW9,IY9,=IQ1QQ/9,=IT9CHU/J,=IT9CKA/CA,=IT9CLY/JZK, - =IT9DSA/CA,=IT9DTU/N,=IT9GDS/WLK,=IT9HBS/LH,=IT9JZK/WLK,=IT9KKE/JZK,=IT9MRM/N,=IT9MRZ/LH, - =IT9NCO/LH,=IT9NCO/N,=IT9OTF/JZK,=IT9RRU/LH,=IT9RYH/J,=IT9RYH/N,=IT9ZSB/LH,=IW0HBY/9; + IB9,ID9,IE9,IF9,II9,IJ9,IO9,IQ9,IR9,IT9,IU9,IW9,IY9,=II0GDF/9,=IQ1QQ/9,=IT9CHU/J,=IT9CKA/CA, + =IT9CLY/JZK,=IT9DSA/CA,=IT9DTU/N,=IT9GDS/WLK,=IT9HBS/LH,=IT9JZK/WLK,=IT9KKE/JZK,=IT9MRM/N, + =IT9MRZ/LH,=IT9NCO/LH,=IT9NCO/N,=IT9OTF/JZK,=IT9RRU/LH,=IT9RYH/J,=IT9RYH/N,=IT9ZSB/LH,=IW0HBY/9; Djibouti: 37: 48: AF: 11.75: -42.35: -3.0: J2: J2; Grenada: 08: 11: NA: 12.13: 61.68: 4.0: J3: @@ -1110,12 +1120,11 @@ Japan: 25: 45: AS: 36.40: -138.38: -9.0: JA: =JD1BHH/6; Minami Torishima: 27: 90: OC: 24.28: -153.97: -10.0: JD/m: =8J1ZIU/JD1,=8N1AQ/JD1,=JA6GXK/JD1,=JD1/8J1ZIU,=JD1/8N1AQ,=JD1/JA6GXK,=JD1/JD1BIC,=JD1/JD1YAB, - =JD1/JE6XPF,=JD1/JF3CTR,=JD1/JF7MTO,=JD1/JF8HIQ,=JD1/JG1RHN,=JD1/JG8NQJ,=JD1/JH1EFP,=JD1/JI2AMA, - =JD1/JK1PCN,=JD1/JR8XXQ,=JD1BCK,=JD1BIC/JD1,=JD1BME,=JD1BMM,=JD1BND,=JD1M/JI2AMA,=JD1YAA, - =JD1YAB/JD1,=JD1YBJ,=JF3CTR/JD1,=JF7MTO/JD1,=JF8HIQ/JD1,=JG1RHN/JD1,=JG8NQJ/JD1,=JH1EFP/JD1, - =JI2AMA/JD1,=JK1PCN/JD1,=JR8XXQ/JD1; + =JD1/JE6XPF,=JD1/JF3CTR,=JD1/JF8HIQ,=JD1/JG1RHN,=JD1/JG8NQJ,=JD1/JH1EFP,=JD1/JI2AMA,=JD1/JK1PCN, + =JD1/JR8XXQ,=JD1BCK,=JD1BIC/JD1,=JD1BME,=JD1BMM,=JD1BND,=JD1M/JI2AMA,=JD1YAA,=JD1YAB/JD1,=JD1YBJ, + =JF3CTR/JD1,=JF8HIQ/JD1,=JG1RHN/JD1,=JG8NQJ/JD1,=JH1EFP/JD1,=JI2AMA/JD1,=JK1PCN/JD1,=JR8XXQ/JD1; Ogasawara: 27: 45: AS: 27.05: -142.20: -9.0: JD/o: - JD1,=8N1OGA; + JD1,=8N1OGA,=JR7ISY/JD1/CM; Mongolia: 23: 32: AS: 46.77: -102.17: -7.0: JT: JT,JU,JV, JT2[33],JU2[33],JV2[33], @@ -1123,7 +1132,7 @@ Mongolia: 23: 32: AS: 46.77: -102.17: -7.0: JT: Svalbard: 40: 18: EU: 78.00: -16.00: -1.0: JW: JW; Bear Island: 40: 18: EU: 74.43: -19.08: -1.0: *JW/b: - =JW0BEA,=JW1I,=JW2US,=JW2VOA,=JW3FL,=JW4GHA,=JW4JSA,=JW4LN,=JW5RIA,=JW7VW,=JW9JKA; + =JW/LB2PG,=JW0BEA,=JW1I,=JW2US,=JW2VOA,=JW3FL,=JW4GHA,=JW4JSA,=JW4LN,=JW5RIA,=JW7VW,=JW9JKA; Jan Mayen: 40: 18: EU: 71.05: 8.28: 1.0: JX: JX; Jordan: 20: 39: AS: 31.18: -36.42: -2.0: JY: @@ -1140,116 +1149,123 @@ United States: 05: 08: NA: 37.53: 91.67: 5.0: K: WE0(4)[7],WF0(4)[7],WG0(4)[7],WI0(4)[7],WJ0(4)[7],WK0(4)[7],WM0(4)[7],WN0(4)[7],WO0(4)[7], WQ0(4)[7],WR0(4)[7],WS0(4)[7],WT0(4)[7],WU0(4)[7],WV0(4)[7],WW0(4)[7],WX0(4)[7],WY0(4)[7], WZ0(4)[7],=AH2BW(4)[7],=AH2BY(4)[7],=AH6ES/0(4)[7],=AH6FY(4)[7],=AH6MD(4)[7],=AH6N(4)[7], - =AH6N/0(4)[7],=AH6O(4)[7],=AH6OS(4)[7],=AH6RS(4)[7],=AL0G(4)[7],=AL3E(4)[7],=AL6E(4)[7], - =AL7BX(4)[7],=AL7EK(4)[7],=AL7FU(4)[7],=AL7GQ(4)[7],=AL7LL(4)[7],=AL7NY(4)[7],=AL7O/0(4)[7], - =AL7OC(4)[7],=AL7QQ(4)[7],=AL7QQ/P(4)[7],=AL9DB(4)[7],=KH0EX(4)[7],=KH2CZ(4)[7],=KH2JK(4)[7], - =KH2OP(4)[7],=KH2OP/0(4)[7],=KH2SL(4)[7],=KH6DM(4)[7],=KH6GN(4)[7],=KH6HNL(4)[7],=KH6HTV/0(4)[7], - =KH6JEM(4)[7],=KH6JFH(4)[7],=KH6NM(4)[7],=KH6NR(4)[7],=KH6RON(4)[7],=KH6SB(4)[7],=KH6TL(4)[7], - =KH6UC(4)[7],=KH6VHF(4)[7],=KH6VO(4)[7],=KH7AL/M(4)[7],=KH7AL/P(4)[7],=KH7BU(4)[7],=KH7GF(4)[7], - =KH7HA(4)[7],=KH7HY(4)[7],=KH7QI(4)[7],=KH7QJ(4)[7],=KH7QT(4)[7],=KH8CW(4)[7],=KL0DW(4)[7], - =KL0EQ(4)[7],=KL0FOX(4)[7],=KL0GP(4)[7],=KL0GQ(4)[7],=KL0MW(4)[7],=KL0UP(4)[7],=KL0WIZ(4)[7], - =KL1HT(4)[7],=KL1IF(4)[7],=KL1IF/M(4)[7],=KL1J(4)[7],=KL1LD(4)[7],=KL1PV(4)[7],=KL1TU(4)[7], - =KL1V/M(4)[7],=KL1VN(4)[7],=KL2A/0(4)[7],=KL2FU(4)[7],=KL2GR(4)[7],=KL2QO(4)[7],=KL2SX(4)[7], - =KL3LY(4)[7],=KL3MA(4)[7],=KL3MB(4)[7],=KL3MC(4)[7],=KL3QS(4)[7],=KL3SM(4)[7],=KL3VN(4)[7], - =KL4IY(4)[7],=KL4JN(4)[7],=KL7DE(4)[7],=KL7DTJ(4)[7],=KL7ED(4)[7],=KL7EP(4)[7],=KL7EP/0(4)[7], - =KL7GKY/0(4)[7],=KL7GLK(4)[7],=KL7GLK/0(4)[7],=KL7GLK/B(4)[7],=KL7IXI(4)[7],=KL7JGJ(4)[7], - =KL7JIE(4)[7],=KL7JIM(4)[7],=KL7JR/0(4)[7],=KL7MH(4)[7],=KL7MV(4)[7],=KL7NW(4)[7],=KL7PE/M(4)[7], - =KL7QW(4)[7],=KL7QW/0(4)[7],=KL7RH(4)[7],=KL7RZ(4)[7],=KL7SB/0(4)[7],=KL7SFD(4)[7],=KL7UV(4)[7], - =KL7XH(4)[7],=KL7YL(4)[7],=KL7YY/0(4)[7],=KL7ZD(4)[7],=KL7ZT(4)[7],=KP4ATV(4)[7],=KP4MLF(4)[7], - =KP4XZ(4)[7],=NH2LH(4)[7],=NH6CF(4)[7],=NH6WF(4)[7],=NH7CY(4)[7],=NH7FI(4)[7],=NH7XM(4)[7], - =NH7ZH(4)[7],=NL7AS(4)[7],=NL7BU(4)[7],=NL7CQ(4)[7],=NL7CQ/0(4)[7],=NL7FF(4)[7],=NL7FU(4)[7], - =NL7XT(4)[7],=NL7XU(4)[7],=NP4AI(4)[7],=NP4AI/0(4)[7],=VE4AGT/M(4)[7],=VE4XC/M(4)[7],=WH2S(4)[7], - =WH6AKZ(4)[7],=WH6ANH(4)[7],=WH6BLT(4)[7],=WH6BUL(4)[7],=WH6BXD(4)[7],=WH6CTU(4)[7],=WH6CUE(4)[7], - =WH6CYM(4)[7],=WH6CZI(4)[7],=WH6CZU(4)[7],=WH6DCJ(4)[7],=WH6DUV(4)[7],=WH6EAE(4)[7],=WH6ENX(4)[7], - =WH6LR(4)[7],=WH6MS(4)[7],=WH6QS(4)[7],=WH7DA(4)[7],=WH7IR(4)[7],=WH7MZ(4)[7],=WH7PV(4)[7], - =WH9AAH(4)[7],=WL0JF(4)[7],=WL1ON(4)[7],=WL7AEC(4)[7],=WL7AJA(4)[7],=WL7ANY(4)[7],=WL7ATK(4)[7], + =AH6N/0(4)[7],=AH6O(4)[7],=AH6OS(4)[7],=AH6PC(4)[7],=AH6RS(4)[7],=AL0G(4)[7],=AL1VE/R(4)[7], + =AL3E(4)[7],=AL6E(4)[7],=AL7BX(4)[7],=AL7EK(4)[7],=AL7FU(4)[7],=AL7GQ(4)[7],=AL7NY(4)[7], + =AL7O/0(4)[7],=AL7OC(4)[7],=AL7QQ(4)[7],=AL7QQ/P(4)[7],=AL9DB(4)[7],=KH0EX(4)[7],=KH2CZ(4)[7], + =KH2JK(4)[7],=KH2OP(4)[7],=KH2OP/0(4)[7],=KH2SL(4)[7],=KH6DM(4)[7],=KH6GN(4)[7],=KH6HNL(4)[7], + =KH6HTV/0(4)[7],=KH6JEM(4)[7],=KH6JFH(4)[7],=KH6NM(4)[7],=KH6NR(4)[7],=KH6RON(4)[7],=KH6SB(4)[7], + =KH6TL(4)[7],=KH6UC(4)[7],=KH6VHF(4)[7],=KH6VO(4)[7],=KH7AL/M(4)[7],=KH7AL/P(4)[7],=KH7BU(4)[7], + =KH7GF(4)[7],=KH7HA(4)[7],=KH7HY(4)[7],=KH7QI(4)[7],=KH7QJ(4)[7],=KH7QT(4)[7],=KH8CW(4)[7], + =KL0DW(4)[7],=KL0EQ(4)[7],=KL0FOX(4)[7],=KL0GP(4)[7],=KL0GQ(4)[7],=KL0MW(4)[7],=KL0N(4)[7], + =KL0SV(4)[7],=KL0UP(4)[7],=KL0WIZ(4)[7],=KL1HT(4)[7],=KL1IF(4)[7],=KL1IF/M(4)[7],=KL1J(4)[7], + =KL1LD(4)[7],=KL1PV(4)[7],=KL1TU(4)[7],=KL1V/M(4)[7],=KL1VN(4)[7],=KL2A/0(4)[7],=KL2FU(4)[7], + =KL2GR(4)[7],=KL2QO(4)[7],=KL2SX(4)[7],=KL3LY(4)[7],=KL3MA(4)[7],=KL3MB(4)[7],=KL3MC(4)[7], + =KL3MW(4)[7],=KL3QS(4)[7],=KL3SM(4)[7],=KL3VN(4)[7],=KL4IY(4)[7],=KL4JN(4)[7],=KL7DE(4)[7], + =KL7DTJ(4)[7],=KL7ED(4)[7],=KL7EP(4)[7],=KL7EP/0(4)[7],=KL7GKY/0(4)[7],=KL7GLK(4)[7], + =KL7GLK/0(4)[7],=KL7GLK/B(4)[7],=KL7IXI(4)[7],=KL7JGJ(4)[7],=KL7JIE(4)[7],=KL7JIM(4)[7], + =KL7JR/0(4)[7],=KL7MH(4)[7],=KL7MV(4)[7],=KL7NW(4)[7],=KL7PE/M(4)[7],=KL7QW(4)[7],=KL7QW/0(4)[7], + =KL7RH(4)[7],=KL7RZ(4)[7],=KL7SB/0(4)[7],=KL7SFD(4)[7],=KL7UV(4)[7],=KL7XH(4)[7],=KL7YL(4)[7], + =KL7YY/0(4)[7],=KL7ZD(4)[7],=KL7ZT(4)[7],=KP4ATV(4)[7],=KP4MLF(4)[7],=KP4XZ(4)[7],=NH2LH(4)[7], + =NH6CF(4)[7],=NH6WF(4)[7],=NH7CY(4)[7],=NH7FI(4)[7],=NH7XM(4)[7],=NH7ZH(4)[7],=NL7AS(4)[7], + =NL7BU(4)[7],=NL7CQ(4)[7],=NL7CQ/0(4)[7],=NL7FF(4)[7],=NL7FU(4)[7],=NL7XT(4)[7],=NL7XU(4)[7], + =NP4AI(4)[7],=NP4AI/0(4)[7],=VE4AGT/M(4)[7],=VE4XC/M(4)[7],=WH2S(4)[7],=WH6AKZ(4)[7], + =WH6ANH(4)[7],=WH6BLT(4)[7],=WH6BUL(4)[7],=WH6BXD(4)[7],=WH6CTU(4)[7],=WH6CUE(4)[7],=WH6CYM(4)[7], + =WH6CZI(4)[7],=WH6CZU(4)[7],=WH6DCJ(4)[7],=WH6DUV(4)[7],=WH6EAE(4)[7],=WH6ENX(4)[7],=WH6LR(4)[7], + =WH6MS(4)[7],=WH6QS(4)[7],=WH7DA(4)[7],=WH7IR(4)[7],=WH7MZ(4)[7],=WH7PV(4)[7],=WH9AAH(4)[7], + =WL0JF(4)[7],=WL1ON(4)[7],=WL7AEC(4)[7],=WL7AJA(4)[7],=WL7ANY(4)[7],=WL7ATK(4)[7],=WL7BRV(4)[7], =WL7BT(4)[7],=WL7CEG(4)[7],=WL7CLI(4)[7],=WL7CPW(4)[7],=WL7CQF(4)[7],=WL7CRT(4)[7],=WL7CY(4)[7], =WL7JB(4)[7],=WL7LZ(4)[7],=WL7LZ/M(4)[7],=WL7RV(4)[7],=WL7YM(4)[7],=WP2B/0(4)[7],=WP3QH(4)[7], - =WP3Y(4)[7],=WP4BTQ(4)[7],=WP4GQR(4)[7],=WP4HRK(4)[7],=WP4LC(4)[7],=WP4NPV(4)[7], + =WP3Y(4)[7],=WP4BTQ(4)[7],=WP4GQR(4)[7],=WP4LC(4)[7],=WP4NPV(4)[7], =AH2V(5)[8],=AH2W(5)[8],=AH6BV(5)[8],=AL0A(5)[8],=AL1O(5)[8],=AL4V(5)[8],=AL6I(5)[8],=AL6L(5)[8], - =AL6M(5)[8],=AL7EL(5)[8],=AL7LV(5)[8],=AL7QS(5)[8],=AL8E(5)[8],=KH2EH(5)[8],=KH6GR(5)[8], - =KH6HZ(5)[8],=KH6IKI(5)[8],=KH6JKQ(5)[8],=KH6JUK(5)[8],=KH6RF(5)[8],=KH6RF/1(5)[8],=KH6RF/M(5)[8], - =KH7CD(5)[8],=KH7CD/1(5)[8],=KH8AC(5)[8],=KH8AC/1(5)[8],=KL1OC(5)[8],=KL1T(5)[8],=KL1WD(5)[8], - =KL2A/1(5)[8],=KL2DM(5)[8],=KL2GA(5)[8],=KL2IC(5)[8],=KL2KL(5)[8],=KL7CE/1(5)[8],=KL7IXX(5)[8], - =KL7JHM(5)[8],=KL7JJN(5)[8],=KL7JR/1(5)[8],=KL7JT(5)[8],=KL7LK(5)[8],=KL7USI/1(5)[8],=KL8DX(5)[8], - =KP4ANG(5)[8],=KP4BLS(5)[8],=KP4BPR(5)[8],=KP4DGF(5)[8],=KP4EC/1(5)[8],=KP4G(5)[8],=KP4GVT(5)[8], - =KP4MR(5)[8],=KP4NPL(5)[8],=KP4NW(5)[8],=KP4R(5)[8],=KP4RCD(5)[8],=NH0H(5)[8],=NH6IH(5)[8], - =NH6XW(5)[8],=NH6ZB(5)[8],=NL7FJ(5)[8],=NL7MO(5)[8],=NL7NJ(5)[8],=NL7OI(5)[8],=NL7OT(5)[8], - =NL9H(5)[8],=NP2FZ(5)[8],=NP2FZ/1(5)[8],=NP2GG(5)[8],=NP2PN(5)[8],=NP3IV(5)[8],=NP3LN(5)[8], - =NP4AO(5)[8],=NP4AZ(5)[8],=NP4ER(5)[8],=VE1BES/M(5)[8],=VE3CMB/M(5)[8],=VE4CCN/M(5)[8], - =WH0EWX(5)[8],=WH2B(5)[8],=WH6CT(5)[8],=WH6DSN(5)[8],=WH6EI(5)[8],=WH6FBH(5)[8],=WH6MY(5)[8], - =WH6SW(5)[8],=WH6SW/1(5)[8],=WH7TP(5)[8],=WL1B(5)[8],=WL7B(5)[8],=WL7CC(5)[8],=WL7CUP(5)[8], - =WL7CVD(5)[8],=WL7WO(5)[8],=WL7WO/1(5)[8],=WL7Z/1(5)[8],=WP2MG(5)[8],=WP3NN(5)[8],=WP3NZ(5)[8], - =WP3QV(5)[8],=WP3QV/1(5)[8],=WP3WV(5)[8],=WP4AKE(5)[8],=WP4AZJ(5)[8],=WP4BC(5)[8],=WP4BF(5)[8], - =WP4CJH(5)[8],=WP4JF(5)[8],=WP4KQ(5)[8],=WP4MKJ(5)[8],=WP4MMV(5)[8],=WP4MOC(5)[8],=WP4NKW(5)[8], - =WP4NUV(5)[8],=WP4NYY(5)[8],=WP4OIG(5)[8],=WP4OJK(5)[8], + =AL6M(5)[8],=AL7EL(5)[8],=AL7LV(5)[8],=AL7QS(5)[8],=AL8E(5)[8],=KH2AB(5)[8],=KH2EH(5)[8], + =KH6GR(5)[8],=KH6HZ(5)[8],=KH6IKI(5)[8],=KH6JKQ(5)[8],=KH6JUK(5)[8],=KH6RF(5)[8],=KH6RF/1(5)[8], + =KH6RF/M(5)[8],=KH7CD(5)[8],=KH7CD/1(5)[8],=KH8AC(5)[8],=KH8AC/1(5)[8],=KL1OC(5)[8],=KL1T(5)[8], + =KL1WD(5)[8],=KL2A/1(5)[8],=KL2DM(5)[8],=KL2GA(5)[8],=KL2IC(5)[8],=KL2KL(5)[8],=KL7CE/1(5)[8], + =KL7IOP(5)[8],=KL7IXX(5)[8],=KL7JHM(5)[8],=KL7JJN(5)[8],=KL7JR/1(5)[8],=KL7JT(5)[8],=KL7LK(5)[8], + =KL7USI/1(5)[8],=KL8DX(5)[8],=KP4ANG(5)[8],=KP4BLS(5)[8],=KP4BPR(5)[8],=KP4DGF(5)[8], + =KP4EC/1(5)[8],=KP4G(5)[8],=KP4GVT(5)[8],=KP4MR(5)[8],=KP4NPL(5)[8],=KP4NW(5)[8],=KP4R(5)[8], + =KP4RCD(5)[8],=KP4ZEM(5)[8],=NH0H(5)[8],=NH6IH(5)[8],=NH6XW(5)[8],=NH6ZB(5)[8],=NL7AK(5)[8], + =NL7FJ(5)[8],=NL7MO(5)[8],=NL7NJ(5)[8],=NL7OI(5)[8],=NL7OT(5)[8],=NL9H(5)[8],=NP2FZ(5)[8], + =NP2FZ/1(5)[8],=NP2GG(5)[8],=NP2PN(5)[8],=NP3IV(5)[8],=NP3LN(5)[8],=NP4AO(5)[8],=NP4AZ(5)[8], + =NP4ER(5)[8],=VE1BES/M(5)[8],=VE3CMB/M(5)[8],=VE4CCN/M(5)[8],=WH0EWX(5)[8],=WH2B(5)[8], + =WH6CT(5)[8],=WH6DSN(5)[8],=WH6EI(5)[8],=WH6FBH(5)[8],=WH6MY(5)[8],=WH6SW(5)[8],=WH6SW/1(5)[8], + =WH7TP(5)[8],=WL1B(5)[8],=WL7B(5)[8],=WL7CC(5)[8],=WL7CUP(5)[8],=WL7CVD(5)[8],=WL7WO(5)[8], + =WL7WO/1(5)[8],=WL7Z/1(5)[8],=WP2MG(5)[8],=WP3NN(5)[8],=WP3QV(5)[8],=WP3QV/1(5)[8],=WP3WV(5)[8], + =WP4AKE(5)[8],=WP4AZJ(5)[8],=WP4BC(5)[8],=WP4BF(5)[8],=WP4CGI(5)[8],=WP4CJH(5)[8],=WP4JF(5)[8], + =WP4KQ(5)[8],=WP4MKJ(5)[8],=WP4MMV(5)[8],=WP4MOC(5)[8],=WP4NKW(5)[8],=WP4NUV(5)[8],=WP4NYY(5)[8], + =WP4OIG(5)[8],=WP4OJK(5)[8], =AH0BR(5)[8],=AH2AL(5)[8],=AH2O(5)[8],=AH6K(5)[8],=AL0Q(5)[8],=AL0Y(5)[8],=AL2O(5)[8], =AL7RG(5)[8],=KH2CW(5)[8],=KH2P(5)[8],=KH2R(5)[8],=KH4AG(5)[8],=KH6ALN(5)[8],=KH6HO(5)[8], - =KH7GA(5)[8],=KH7JO(5)[8],=KH7JO/2(5)[8],=KH7MX(5)[8],=KH7NE(5)[8],=KH8ZK(5)[8],=KL0WV(5)[8], - =KL1A/2(5)[8],=KL2A/2(5)[8],=KL2NP(5)[8],=KL3DY(5)[8],=KL3ET(5)[8],=KL3ZC(5)[8],=KL4T(5)[8], + =KH7GA(5)[8],=KH7JO(5)[8],=KH7JO/2(5)[8],=KH7MX(5)[8],=KH7NE(5)[8],=KH8ZK(5)[8],=KL0TV(5)[8], + =KL0WV(5)[8],=KL1A/2(5)[8],=KL2A/2(5)[8],=KL2NP(5)[8],=KL3ET(5)[8],=KL3ZC(5)[8],=KL4T(5)[8], =KL7DL(5)[8],=KL7GB(5)[8],=KL7JCQ(5)[8],=KL7NL/2(5)[8],=KL7TJZ(5)[8],=KL7USI/2(5)[8],=KL7WA(5)[8], - =KL9ER(5)[8],=KP2NP(5)[8],=KP3AK(5)[8],=KP3LM(5)[8],=KP3S(5)[8],=KP3Y(5)[8],=KP4AK(5)[8], - =KP4C(5)[8],=KP4CML(5)[8],=KP4GEG(5)[8],=KP4HR(5)[8],=KP4I(5)[8],=KP4JDR(5)[8],=KP4JMP(5)[8], - =NH2DC(5)[8],=NL7CC(5)[8],=NP2AQ(5)[8],=NP2GI(5)[8],=NP3D(5)[8],=NP3E(5)[8],=NP3EU(5)[8], - =NP3I(5)[8],=NP3KH(5)[8],=NP3KP(5)[8],=NP4IR(5)[8],=NP4IT(5)[8],=NP4JQ(5)[8],=WH0W(5)[8], - =WH2C(5)[8],=WH6DLD(5)[8],=WH6DNT(5)[8],=WH6UO(5)[8],=WL2NAS(5)[8],=WL7OG(5)[8],=WP2AAO(5)[8], - =WP3MD(5)[8],=WP3VU(5)[8],=WP3WZ(5)[8],=WP4AR(5)[8],=WP4BMU(5)[8],=WP4BNI(5)[8],=WP4BZ(5)[8], - =WP4CB(5)[8],=WP4DME(5)[8],=WP4DWH(5)[8],=WP4EHY(5)[8],=WP4EYW(5)[8],=WP4HLY(5)[8],=WP4HXS(5)[8], - =WP4LYI(5)[8],=WP4MQN(5)[8],=WP4MRB(5)[8],=WP4MUJ(5)[8],=WP4MYM(5)[8],=WP4MZO(5)[8],=WP4NBS(5)[8], - =WP4OCO(5)[8],=WP4OPY(5)[8],=WP4PZB(5)[8],=WP4R(5)[8],=XL3TUV/M(5)[8],=XM3CMB/M(5)[8], + =KL9ER(5)[8],=KP2NP(5)[8],=KP3AK(5)[8],=KP3LM(5)[8],=KP3Y(5)[8],=KP4AK(5)[8],=KP4CML(5)[8], + =KP4GEG(5)[8],=KP4HR(5)[8],=KP4I(5)[8],=KP4JDR(5)[8],=KP4JMP(5)[8],=NH2DC(5)[8],=NH7NA(5)[8], + =NH7TN(5)[8],=NL7CC(5)[8],=NP2AQ(5)[8],=NP2GI(5)[8],=NP3D(5)[8],=NP3E(5)[8],=NP3EU(5)[8], + =NP3I(5)[8],=NP3KH(5)[8],=NP3KP(5)[8],=NP4H(5)[8],=NP4IR(5)[8],=NP4IT(5)[8],=NP4JQ(5)[8], + =WH0W(5)[8],=WH2C(5)[8],=WH6DLD(5)[8],=WH6DNT(5)[8],=WH6UO(5)[8],=WL2NAS(5)[8],=WL7OG(5)[8], + =WP2AAO(5)[8],=WP3MD(5)[8],=WP3VU(5)[8],=WP3WZ(5)[8],=WP4AR(5)[8],=WP4BMU(5)[8],=WP4BNI(5)[8], + =WP4BZ(5)[8],=WP4CB(5)[8],=WP4DME(5)[8],=WP4DWH(5)[8],=WP4EHY(5)[8],=WP4EYW(5)[8],=WP4HLY(5)[8], + =WP4HXS(5)[8],=WP4KXX(5)[8],=WP4LYI(5)[8],=WP4MQN(5)[8],=WP4MRB(5)[8],=WP4MUJ(5)[8],=WP4MYM(5)[8], + =WP4MZO(5)[8],=WP4NBS(5)[8],=WP4NZF(5)[8],=WP4OCO(5)[8],=WP4OPY(5)[8],=WP4PZB(5)[8],=WP4R(5)[8], + =XL3TUV/M(5)[8],=XM3CMB/M(5)[8], =4U1WB(5)[8],=AH6AX(5)[8],=AH6FF/3(5)[8],=AH6R(5)[8],=AH6Z(5)[8],=AH7J(5)[8],=AH8P(5)[8], =AL1B(5)[8],=AL1B/M(5)[8],=AL7AB(5)[8],=AL7NN(5)[8],=AL7NN/3(5)[8],=AL7RS(5)[8],=KH2GM(5)[8], =KH2JX(5)[8],=KH2SX(5)[8],=KH6CUJ(5)[8],=KH6ILR/3(5)[8],=KH6JGA(5)[8],=KH6LDO(5)[8],=KH8CN(5)[8], - =KL1KM(5)[8],=KL2A(5)[8],=KL2A/3(5)[8],=KL2BV(5)[8],=KL2XF(5)[8],=KL3JC(5)[8],=KL7FD(5)[8], - =KL7GLK/3(5)[8],=KL7HR/3(5)[8],=KL7JO(5)[8],=KL7OF/3(5)[8],=KL7OQ(5)[8],=KL9A/3(5)[8],=KP3M(5)[8], - =KP4CAM(5)[8],=KP4FCF(5)[8],=KP4GB/3(5)[8],=KP4IP(5)[8],=KP4JB(5)[8],=KP4N(5)[8],=KP4N/3(5)[8], - =KP4PRI(5)[8],=KP4UV(5)[8],=KP4WR(5)[8],=KP4XO(5)[8],=KP4XX(5)[8],=NH2CW(5)[8],=NH6BD(5)[8], - =NH6BK(5)[8],=NH7C(5)[8],=NH7CC(5)[8],=NH7YK(5)[8],=NL7CK(5)[8],=NL7PJ(5)[8],=NL7V/3(5)[8], - =NL7XM(5)[8],=NL7XM/B(5)[8],=NP2EP(5)[8],=NP2G(5)[8],=NP2NC(5)[8],=NP3ES(5)[8],=NP3IP(5)[8], - =NP3YN(5)[8],=NP4RH(5)[8],=NP4YZ(5)[8],=WH6ADS(5)[8],=WH6AWO(5)[8],=WH6AZN(5)[8],=WH6CE(5)[8], - =WH6CTO(5)[8],=WH6DOA(5)[8],=WH6ECO(5)[8],=WH6EEL(5)[8],=WH6EEN(5)[8],=WH6EIJ(5)[8],=WH6IO(5)[8], - =WH6OB(5)[8],=WH7F(5)[8],=WH7USA(5)[8],=WL7AF(5)[8],=WL7L(5)[8],=WP2XX(5)[8],=WP3BX(5)[8], - =WP3CC(5)[8],=WP3EC(5)[8],=WP3FK(5)[8],=WP4DA(5)[8],=WP4DCK(5)[8],=WP4EDM(5)[8],=WP4GJL(5)[8], + =KL1HA(5)[8],=KL1KM(5)[8],=KL2A(5)[8],=KL2A/3(5)[8],=KL2BV(5)[8],=KL2XF(5)[8],=KL3JC(5)[8], + =KL7FD(5)[8],=KL7GLK/3(5)[8],=KL7HR/3(5)[8],=KL7JO(5)[8],=KL7OF/3(5)[8],=KL7OQ(5)[8], + =KL9A/3(5)[8],=KP3M(5)[8],=KP4BEP(5)[8],=KP4CAM(5)[8],=KP4FCF(5)[8],=KP4GB/3(5)[8],=KP4IP(5)[8], + =KP4JB(5)[8],=KP4N(5)[8],=KP4N/3(5)[8],=KP4PRI(5)[8],=KP4UV(5)[8],=KP4WR(5)[8],=KP4XO(5)[8], + =KP4XX(5)[8],=KP4YH(5)[8],=NH2CW(5)[8],=NH2LA(5)[8],=NH6BD(5)[8],=NH6BK(5)[8],=NH7C(5)[8], + =NH7CC(5)[8],=NH7YK(5)[8],=NL7CK(5)[8],=NL7PJ(5)[8],=NL7V/3(5)[8],=NL7XM(5)[8],=NL7XM/B(5)[8], + =NP2EP(5)[8],=NP2G(5)[8],=NP2NC(5)[8],=NP3ES(5)[8],=NP3IP(5)[8],=NP3YN(5)[8],=NP4RH(5)[8], + =NP4YZ(5)[8],=WH6ADS(5)[8],=WH6AWO(5)[8],=WH6AZN(5)[8],=WH6CE(5)[8],=WH6CTO(5)[8],=WH6DOA(5)[8], + =WH6ECO(5)[8],=WH6EEL(5)[8],=WH6EEN(5)[8],=WH6EIJ(5)[8],=WH6IO(5)[8],=WH6OB(5)[8],=WH7F(5)[8], + =WH7USA(5)[8],=WL7AF(5)[8],=WL7AQ(5)[8],=WL7L(5)[8],=WP2XX(5)[8],=WP3BX(5)[8],=WP3CC(5)[8], + =WP3EC(5)[8],=WP3FK(5)[8],=WP4DA(5)[8],=WP4DCK(5)[8],=WP4EDM(5)[8],=WP4GJL(5)[8],=WP4HRK(5)[8], =WP4HSZ(5)[8],=WP4KDN(5)[8],=WP4KKX(5)[8],=WP4LEM(5)[8],=WP4LNP(5)[8],=WP4MNV(5)[8],=WP4MSX(5)[8], - =WP4MYN(5)[8],=WP4OSQ(5)[8],=WP4PPH(5)[8],=WP4PQN(5)[8],=WP4PUR(5)[8],=WP4PYL(5)[8],=WP4PYM(5)[8], - =WP4PYN(5)[8],=WP4PYT(5)[8],=WP4PYU(5)[8],=WP4PYV(5)[8],=WP4PYZ(5)[8],=WP4PZA(5)[8], - =AH0BV(5)[8],=AH0BZ(5)[8],=AH2AJ(5)[8],=AH2AM(5)[8],=AH2DF(5)[8],=AH2EB(5)[8],=AH2X(5)[8], - =AH3B(5)[8],=AH6AL(5)[8],=AH6AT(5)[8],=AH6AU(5)[8],=AH6BJ(5)[8],=AH6EZ/4(5)[8],=AH6FX(5)[8], - =AH6FX/4(5)[8],=AH6IC(5)[8],=AH6IJ(5)[8],=AH6IW(5)[8],=AH6JN/4(5)[8],=AH6JN/M(5)[8],=AH6KT(5)[8], - =AH6KT/4(5)[8],=AH6LS(5)[8],=AH6OB(5)[8],=AH6TI(5)[8],=AH7I/4(5)[8],=AH7MI(5)[8],=AH8B(5)[8], - =AH8M(5)[8],=AH8M/M(5)[8],=AH8T(5)[8],=AL0I(5)[8],=AL1A(5)[8],=AL3G(5)[8],=AL3M(5)[8],=AL4T(5)[8], + =WP4MYN(5)[8],=WP4NXG(5)[8],=WP4OSQ(5)[8],=WP4PPH(5)[8],=WP4PQN(5)[8],=WP4PUR(5)[8],=WP4PYL(5)[8], + =WP4PYM(5)[8],=WP4PYN(5)[8],=WP4PYT(5)[8],=WP4PYU(5)[8],=WP4PYV(5)[8],=WP4PYZ(5)[8],=WP4PZA(5)[8], + =AH0BV(5)[8],=AH0BZ(5)[8],=AH0G(5)[8],=AH2AJ(5)[8],=AH2AM(5)[8],=AH2AV/4(5)[8],=AH2DF(5)[8], + =AH2EB(5)[8],=AH2X(5)[8],=AH3B(5)[8],=AH6AL(5)[8],=AH6AT(5)[8],=AH6AU(5)[8],=AH6BJ(5)[8], + =AH6C(5)[8],=AH6EZ/4(5)[8],=AH6FX(5)[8],=AH6FX/4(5)[8],=AH6IC(5)[8],=AH6IJ(5)[8],=AH6IW(5)[8], + =AH6JH(5)[8],=AH6JN/4(5)[8],=AH6JN/M(5)[8],=AH6KS(5)[8],=AH6KT(5)[8],=AH6KT/4(5)[8],=AH6LS(5)[8], + =AH6OB(5)[8],=AH6TI(5)[8],=AH7I(5)[8],=AH7I/4(5)[8],=AH7MI(5)[8],=AH8B(5)[8],=AH8M(5)[8], + =AH8M/M(5)[8],=AH8T(5)[8],=AL0I(5)[8],=AL1A(5)[8],=AL3G(5)[8],=AL3M(5)[8],=AL4T(5)[8], =AL4T/4(5)[8],=AL4U(5)[8],=AL4X(5)[8],=AL5A(5)[8],=AL7AL(5)[8],=AL7AM(5)[8],=AL7BA(5)[8], =AL7GF(5)[8],=AL7GK(5)[8],=AL7HG(5)[8],=AL7HW(5)[8],=AL7HW/4(5)[8],=AL7IS(5)[8],=AL7KT(5)[8], =AL7LH(5)[8],=AL7NL(5)[8],=AL7NM(5)[8],=AL7NS(5)[8],=AL7NS/140(5)[8],=AL7PL(5)[8],=AL7QI(5)[8], =AL7RE(5)[8],=AL7RL(5)[8],=G8ERJ(5)[8],=GO4AZM(5)[8],=GQ4AZM(5)[8],=GR4AZM(5)[8],=KH0CW(5)[8], - =KH0NI(5)[8],=KH0ZZ(5)[8],=KH2BX(5)[8],=KH2D(5)[8],=KH2D/4(5)[8],=KH2GUM/P(5)[8],=KH2HB(5)[8], - =KH2KD(5)[8],=KH2N(5)[8],=KH2NC(5)[8],=KH2PM(5)[8],=KH2RL(5)[8],=KH2TI(5)[8],=KH2UV(5)[8], - =KH2VM(5)[8],=KH3AC(5)[8],=KH3AG(5)[8],=KH6AME(5)[8],=KH6CG(5)[8],=KH6CG/4(5)[8],=KH6CT(5)[8], - =KH6ED(5)[8],=KH6HHS(5)[8],=KH6HHS/4(5)[8],=KH6HOW(5)[8],=KH6ILR(5)[8],=KH6ILR/4(5)[8], - =KH6ITI(5)[8],=KH6JAU(5)[8],=KH6JIM(5)[8],=KH6JJD(5)[8],=KH6JUA(5)[8],=KH6M(5)[8],=KH6M/4(5)[8], - =KH6M/M(5)[8],=KH6MT(5)[8],=KH6MT/4(5)[8],=KH6NC(5)[8],=KH6NI(5)[8],=KH6OU(5)[8],=KH6POI(5)[8], - =KH6PU(5)[8],=KH6RP(5)[8],=KH6TY(5)[8],=KH6TY/R(5)[8],=KH6UN(5)[8],=KH6XH(5)[8],=KH7DM(5)[8], - =KH7DY(5)[8],=KH7FC(5)[8],=KH7GZ(5)[8],=KH7HJ/4(5)[8],=KH7OC(5)[8],=KH7OV(5)[8],=KH7WK(5)[8], - =KH7XS/4(5)[8],=KH7XT(5)[8],=KH7ZC(5)[8],=KH8BB(5)[8],=KH8DO(5)[8],=KL0AG(5)[8],=KL0IP(5)[8], - =KL0KC(5)[8],=KL0KE/4(5)[8],=KL0L(5)[8],=KL0MG(5)[8],=KL0MP(5)[8],=KL0S(5)[8],=KL0SS(5)[8], - =KL0TY(5)[8],=KL0VU(5)[8],=KL0WF(5)[8],=KL1KP(5)[8],=KL1NK(5)[8],=KL1NS(5)[8],=KL1OK(5)[8], - =KL1PA(5)[8],=KL1SS(5)[8],=KL2AK(5)[8],=KL2CX(5)[8],=KL2EY(5)[8],=KL2GG(5)[8],=KL2GP(5)[8], - =KL2HV(5)[8],=KL2MQ(5)[8],=KL2UQ(5)[8],=KL2XI(5)[8],=KL3EV(5)[8],=KL3HG(5)[8],=KL3IA(5)[8], + =KH0HR(5)[8],=KH0NI(5)[8],=KH0ZZ(5)[8],=KH2BX(5)[8],=KH2D(5)[8],=KH2D/4(5)[8],=KH2GUM/P(5)[8], + =KH2HB(5)[8],=KH2KD(5)[8],=KH2N(5)[8],=KH2NC(5)[8],=KH2PM(5)[8],=KH2RL(5)[8],=KH2TI(5)[8], + =KH2UG(5)[8],=KH2UV(5)[8],=KH2VM(5)[8],=KH3AC(5)[8],=KH3AG(5)[8],=KH6AME(5)[8],=KH6CG(5)[8], + =KH6CG/4(5)[8],=KH6CT(5)[8],=KH6ED(5)[8],=KH6HHS(5)[8],=KH6HHS/4(5)[8],=KH6HOW(5)[8], + =KH6ILR(5)[8],=KH6ILR/4(5)[8],=KH6ITI(5)[8],=KH6JAU(5)[8],=KH6JIM(5)[8],=KH6JJD(5)[8], + =KH6JNW(5)[8],=KH6JUA(5)[8],=KH6KZ(5)[8],=KH6M(5)[8],=KH6M/4(5)[8],=KH6M/M(5)[8],=KH6MT(5)[8], + =KH6MT/4(5)[8],=KH6NC(5)[8],=KH6NI(5)[8],=KH6OU(5)[8],=KH6POI(5)[8],=KH6PU(5)[8],=KH6RP(5)[8], + =KH6TY(5)[8],=KH6TY/R(5)[8],=KH6UN(5)[8],=KH6XH(5)[8],=KH7DM(5)[8],=KH7DY(5)[8],=KH7FC(5)[8], + =KH7GM(5)[8],=KH7GZ(5)[8],=KH7HJ/4(5)[8],=KH7OC(5)[8],=KH7OV(5)[8],=KH7WK(5)[8],=KH7XS/4(5)[8], + =KH7XT(5)[8],=KH7ZC(5)[8],=KH8BB(5)[8],=KH8DO(5)[8],=KL0AG(5)[8],=KL0IP(5)[8],=KL0KC(5)[8], + =KL0KE/4(5)[8],=KL0L(5)[8],=KL0MG(5)[8],=KL0MP(5)[8],=KL0S(5)[8],=KL0SS(5)[8],=KL0TY(5)[8], + =KL0VU(5)[8],=KL0WF(5)[8],=KL1KP(5)[8],=KL1NK(5)[8],=KL1NS(5)[8],=KL1OK(5)[8],=KL1PA(5)[8], + =KL1SS(5)[8],=KL2AK(5)[8],=KL2CX(5)[8],=KL2EY(5)[8],=KL2GG(5)[8],=KL2GP(5)[8],=KL2HV(5)[8], + =KL2MQ(5)[8],=KL2NN(5)[8],=KL2UQ(5)[8],=KL2XI(5)[8],=KL3EV(5)[8],=KL3HG(5)[8],=KL3IA(5)[8], =KL3KB(5)[8],=KL3KG(5)[8],=KL3NR(5)[8],=KL3WM(5)[8],=KL3X(5)[8],=KL3XB(5)[8],=KL4CO(5)[8], =KL4DD(5)[8],=KL4H(5)[8],=KL4J(5)[8],=KL5X(5)[8],=KL5YJ(5)[8],=KL7A(5)[8],=KL7DA(5)[8], =KL7DA/4(5)[8],=KL7FO(5)[8],=KL7GLL(5)[8],=KL7H(5)[8],=KL7HIM(5)[8],=KL7HNY(5)[8],=KL7HOT(5)[8], - =KL7HQW(5)[8],=KL7HX(5)[8],=KL7IEK(5)[8],=KL7IKZ(5)[8],=KL7IV(5)[8],=KL7IVY(5)[8],=KL7IWF(5)[8], - =KL7JR(5)[8],=KL7LS(5)[8],=KL7MJ(5)[8],=KL7NCO(5)[8],=KL7NL(5)[8],=KL7NL/4(5)[8],=KL7NT(5)[8], - =KL7P/4(5)[8],=KL7QH(5)[8],=KL7QU(5)[8],=KL7SR(5)[8],=KL7USI/4(5)[8],=KL7XA(5)[8],=KL9A/1(5)[8], - =KP2AF(5)[8],=KP2AV(5)[8],=KP2AV/4(5)[8],=KP2CH(5)[8],=KP2CR(5)[8],=KP2L(5)[8],=KP2L/4(5)[8], - =KP2N(5)[8],=KP2R(5)[8],=KP2U(5)[8],=KP2US(5)[8],=KP2V(5)[8],=KP3AMG(5)[8],=KP3BL(5)[8], - =KP3BP(5)[8],=KP3J(5)[8],=KP3SK(5)[8],=KP3U(5)[8],=KP4AD(5)[8],=KP4AOD(5)[8],=KP4AOD/4(5)[8], - =KP4BEC(5)[8],=KP4BM(5)[8],=KP4BOB(5)[8],=KP4CBP(5)[8],=KP4CEL(5)[8],=KP4CH(5)[8],=KP4CPP(5)[8], - =KP4CSJ(5)[8],=KP4CSZ(5)[8],=KP4CW(5)[8],=KP4CZ(5)[8],=KP4DAC(5)[8],=KP4DDS(5)[8],=KP4DPQ(5)[8], - =KP4DQS(5)[8],=KP4EIA(5)[8],=KP4EMY(5)[8],=KP4ENK(5)[8],=KP4EOR(5)[8],=KP4EOR/4(5)[8], - =KP4ERT(5)[8],=KP4ESC(5)[8],=KP4FBS(5)[8],=KP4FGI(5)[8],=KP4FIR(5)[8],=KP4FJE(5)[8],=KP4FLP(5)[8], - =KP4FOF(5)[8],=KP4HE(5)[8],=KP4HF(5)[8],=KP4HN(5)[8],=KP4II(5)[8],=KP4IRI(5)[8],=KP4IT(5)[8], - =KP4JC(5)[8],=KP4JCC(5)[8],=KP4JWR(5)[8],=KP4KA(5)[8],=KP4KD(5)[8],=KP4KD/4(5)[8],=KP4LEU(5)[8], + =KL7HQW(5)[8],=KL7HX(5)[8],=KL7I(5)[8],=KL7IEK(5)[8],=KL7IKZ(5)[8],=KL7IV(5)[8],=KL7IVY(5)[8], + =KL7IWF(5)[8],=KL7JDS(5)[8],=KL7JR(5)[8],=KL7LS(5)[8],=KL7MJ(5)[8],=KL7NCO(5)[8],=KL7NL(5)[8], + =KL7NL/4(5)[8],=KL7NT(5)[8],=KL7P/4(5)[8],=KL7QH(5)[8],=KL7QU(5)[8],=KL7SR(5)[8],=KL7USI/4(5)[8], + =KL7XA(5)[8],=KL9A/1(5)[8],=KP2AF(5)[8],=KP2AV(5)[8],=KP2AV/4(5)[8],=KP2CH(5)[8],=KP2CR(5)[8], + =KP2L(5)[8],=KP2L/4(5)[8],=KP2N(5)[8],=KP2R(5)[8],=KP2U(5)[8],=KP2US(5)[8],=KP2V(5)[8], + =KP3AMG(5)[8],=KP3BL(5)[8],=KP3BP(5)[8],=KP3J(5)[8],=KP3SK(5)[8],=KP3U(5)[8],=KP4AD(5)[8], + =KP4AOD(5)[8],=KP4AOD/4(5)[8],=KP4BBN(5)[8],=KP4BEC(5)[8],=KP4BM(5)[8],=KP4BOB(5)[8], + =KP4CBP(5)[8],=KP4CEL(5)[8],=KP4CH(5)[8],=KP4CPP(5)[8],=KP4CSJ(5)[8],=KP4CSZ(5)[8],=KP4CW(5)[8], + =KP4CZ(5)[8],=KP4DAC(5)[8],=KP4DDS(5)[8],=KP4DPQ(5)[8],=KP4DQS(5)[8],=KP4EDL(5)[8],=KP4EIA(5)[8], + =KP4EMY(5)[8],=KP4ENK(5)[8],=KP4EOR(5)[8],=KP4EOR/4(5)[8],=KP4ERT(5)[8],=KP4ESC(5)[8], + =KP4FBS(5)[8],=KP4FGI(5)[8],=KP4FIR(5)[8],=KP4FJE(5)[8],=KP4FLP(5)[8],=KP4FOF(5)[8],=KP4HE(5)[8], + =KP4HF(5)[8],=KP4HN(5)[8],=KP4II(5)[8],=KP4IRI(5)[8],=KP4IT(5)[8],=KP4JC(5)[8],=KP4JCC(5)[8], + =KP4JOS(5)[8],=KP4JWR(5)[8],=KP4KA(5)[8],=KP4KD(5)[8],=KP4KD/4(5)[8],=KP4KE/4(5)[8],=KP4LEU(5)[8], =KP4LF(5)[8],=KP4LUV(5)[8],=KP4LX(5)[8],=KP4MA(5)[8],=KP4MPR(5)[8],=KP4MSP(5)[8],=KP4NI(5)[8], =KP4OO(5)[8],=KP4PC(5)[8],=KP4PF(5)[8],=KP4PMD(5)[8],=KP4Q(5)[8],=KP4QT(5)[8],=KP4QT/4(5)[8], =KP4REY(5)[8],=KP4RGT(5)[8],=KP4ROP(5)[8],=KP4RRC(5)[8],=KP4RT(5)[8],=KP4RZ(5)[8],=KP4SU(5)[8], @@ -1259,22 +1275,23 @@ United States: 05: 08: NA: 37.53: 91.67: 5.0: K: =NH6HX(5)[8],=NH6HX/4(5)[8],=NH6JX(5)[8],=NH6KI(5)[8],=NH6QR(5)[8],=NH6SR(5)[8],=NH6T(5)[8], =NH6TL(5)[8],=NH7AA(5)[8],=NH7AQ(5)[8],=NH7AR(5)[8],=NH7FG(5)[8],=NH7OI(5)[8],=NH7T/4(5)[8], =NH7UN(5)[8],=NH7XN(5)[8],=NL5L(5)[8],=NL7AJ(5)[8],=NL7AU(5)[8],=NL7AU/4(5)[8],=NL7BV(5)[8], - =NL7KX(5)[8],=NL7LO(5)[8],=NL7LR(5)[8],=NL7LY(5)[8],=NL7MD(5)[8],=NL7MR(5)[8],=NL7OB(5)[8], - =NL7OS(5)[8],=NL7P(5)[8],=NL7PV(5)[8],=NL7U(5)[8],=NL7VV(5)[8],=NL7VX(5)[8],=NL7VX/4(5)[8], - =NL7VX/M(5)[8],=NL7YZ(5)[8],=NP2B(5)[8],=NP2B/4(5)[8],=NP2BB(5)[8],=NP2BW(5)[8],=NP2C(5)[8], - =NP2C/4(5)[8],=NP2CB(5)[8],=NP2D(5)[8],=NP2DJ(5)[8],=NP2EI(5)[8],=NP2FT(5)[8],=NP2GN(5)[8], - =NP2GW(5)[8],=NP2HQ(5)[8],=NP2HS(5)[8],=NP2HW(5)[8],=NP2IE(5)[8],=NP2IF(5)[8],=NP2IJ(5)[8], - =NP2IS(5)[8],=NP2IW(5)[8],=NP2IX(5)[8],=NP2JA(5)[8],=NP2JS(5)[8],=NP2LC(5)[8],=NP2MM(5)[8], - =NP2MN(5)[8],=NP2MP(5)[8],=NP2MR(5)[8],=NP2MR/4(5)[8],=NP2O(5)[8],=NP2OL(5)[8],=NP2OO(5)[8], - =NP2PA(5)[8],=NP2R(5)[8],=NP2T(5)[8],=NP2W(5)[8],=NP3AX(5)[8],=NP3BL(5)[8],=NP3CC(5)[8], - =NP3CI(5)[8],=NP3CM(5)[8],=NP3CT(5)[8],=NP3FR(5)[8],=NP3G(5)[8],=NP3HD(5)[8],=NP3HG(5)[8], - =NP3HN(5)[8],=NP3HP(5)[8],=NP3HU(5)[8],=NP3IL(5)[8],=NP3IU(5)[8],=NP3K(5)[8],=NP3KM(5)[8], - =NP3MM(5)[8],=NP3MX(5)[8],=NP3NC(5)[8],=NP3OW(5)[8],=NP3QT(5)[8],=NP3R(5)[8],=NP3ST(5)[8], - =NP3TM(5)[8],=NP3UM(5)[8],=NP3VJ(5)[8],=NP4AS(5)[8],=NP4AV(5)[8],=NP4CC(5)[8],=NP4CK(5)[8], - =NP4CV(5)[8],=NP4DM(5)[8],=NP4EM(5)[8],=NP4GH(5)[8],=NP4GW(5)[8],=NP4J(5)[8],=NP4JU(5)[8], - =NP4KV(5)[8],=NP4M(5)[8],=NP4ND(5)[8],=NP4PF(5)[8],=NP4RJ(5)[8],=NP4SY(5)[8],=NP4WT(5)[8], - =NP4XB(5)[8],=WH2AAT(5)[8],=WH2ABJ(5)[8],=WH2G(5)[8],=WH6A(5)[8],=WH6ACF(5)[8],=WH6AJS(5)[8], - =WH6AQ(5)[8],=WH6AVU(5)[8],=WH6AX(5)[8],=WH6BRQ(5)[8],=WH6CMT(5)[8],=WH6CNC(5)[8],=WH6CTC(5)[8], + =NL7KL(5)[8],=NL7KX(5)[8],=NL7LO(5)[8],=NL7LR(5)[8],=NL7LY(5)[8],=NL7MD(5)[8],=NL7MR(5)[8], + =NL7OB(5)[8],=NL7OS(5)[8],=NL7P(5)[8],=NL7PV(5)[8],=NL7U(5)[8],=NL7VV(5)[8],=NL7VX(5)[8], + =NL7VX/4(5)[8],=NL7VX/M(5)[8],=NL7YZ(5)[8],=NP2B(5)[8],=NP2B/4(5)[8],=NP2BB(5)[8],=NP2BW(5)[8], + =NP2C(5)[8],=NP2C/4(5)[8],=NP2CB(5)[8],=NP2D(5)[8],=NP2DJ(5)[8],=NP2EI(5)[8],=NP2FT(5)[8], + =NP2GN(5)[8],=NP2GW(5)[8],=NP2HQ(5)[8],=NP2HS(5)[8],=NP2HW(5)[8],=NP2IE(5)[8],=NP2IF(5)[8], + =NP2IJ(5)[8],=NP2IS(5)[8],=NP2IW(5)[8],=NP2IX(5)[8],=NP2JA(5)[8],=NP2JS(5)[8],=NP2L(5)[8], + =NP2LC(5)[8],=NP2MM(5)[8],=NP2MN(5)[8],=NP2MP(5)[8],=NP2MR(5)[8],=NP2MR/4(5)[8],=NP2O(5)[8], + =NP2OL(5)[8],=NP2OO(5)[8],=NP2OR(5)[8],=NP2PA(5)[8],=NP2R(5)[8],=NP2T(5)[8],=NP2W(5)[8], + =NP3AX(5)[8],=NP3BL(5)[8],=NP3CC(5)[8],=NP3CI(5)[8],=NP3CM(5)[8],=NP3CT(5)[8],=NP3FR(5)[8], + =NP3G(5)[8],=NP3HD(5)[8],=NP3HG(5)[8],=NP3HN(5)[8],=NP3HP(5)[8],=NP3HU(5)[8],=NP3IL(5)[8], + =NP3IU(5)[8],=NP3K(5)[8],=NP3KM(5)[8],=NP3MM(5)[8],=NP3MX(5)[8],=NP3NC(5)[8],=NP3OW(5)[8], + =NP3QT(5)[8],=NP3R(5)[8],=NP3ST(5)[8],=NP3TM(5)[8],=NP3UM(5)[8],=NP3VJ(5)[8],=NP3WX(5)[8], + =NP4AS(5)[8],=NP4AV(5)[8],=NP4CC(5)[8],=NP4CK(5)[8],=NP4CV(5)[8],=NP4DM(5)[8],=NP4EM(5)[8], + =NP4GH(5)[8],=NP4GW(5)[8],=NP4J(5)[8],=NP4JL(5)[8],=NP4JU(5)[8],=NP4KV(5)[8],=NP4M(5)[8], + =NP4ND(5)[8],=NP4PF(5)[8],=NP4RJ(5)[8],=NP4SY(5)[8],=NP4TR(5)[8],=NP4WT(5)[8],=NP4XB(5)[8], + =WH2AAT(5)[8],=WH2ABJ(5)[8],=WH2G(5)[8],=WH6A(5)[8],=WH6ACF(5)[8],=WH6AJS(5)[8],=WH6AQ(5)[8], + =WH6AVU(5)[8],=WH6AX(5)[8],=WH6BRQ(5)[8],=WH6CEF(5)[8],=WH6CMT(5)[8],=WH6CNC(5)[8],=WH6CTC(5)[8], =WH6CXA(5)[8],=WH6CXT(5)[8],=WH6DBX(5)[8],=WH6DMJ(5)[8],=WH6DNF(5)[8],=WH6DOL(5)[8],=WH6DUJ(5)[8], =WH6DXT(5)[8],=WH6EFI(5)[8],=WH6EIK(5)[8],=WH6EKW(5)[8],=WH6ELG(5)[8],=WH6ELM(5)[8],=WH6ETE(5)[8], =WH6ETF(5)[8],=WH6FCP(5)[8],=WH6FGK(5)[8],=WH6HA(5)[8],=WH6IF(5)[8],=WH6IZ(5)[8],=WH6J(5)[8], @@ -1284,22 +1301,23 @@ United States: 05: 08: NA: 37.53: 91.67: 5.0: K: =WL7AX(5)[8],=WL7BAL(5)[8],=WL7CHA(5)[8],=WL7CIB(5)[8],=WL7CKJ(5)[8],=WL7COL(5)[8],=WL7CQT(5)[8], =WL7CUY(5)[8],=WL7E/4(5)[8],=WL7GV(5)[8],=WL7SR(5)[8],=WL7UN(5)[8],=WL7WN(5)[8],=WL7YX(5)[8], =WP2AGD(5)[8],=WP2AGO(5)[8],=WP2AHC(5)[8],=WP2AIG(5)[8],=WP2BB(5)[8],=WP2C(5)[8],=WP2L(5)[8], - =WP2MA(5)[8],=WP2P(5)[8],=WP3AY(5)[8],=WP3BC(5)[8],=WP3JQ(5)[8],=WP3JU(5)[8],=WP3K(5)[8], - =WP3LE(5)[8],=WP3MB(5)[8],=WP3ME(5)[8],=WP3NIS(5)[8],=WP3O(5)[8],=WP3TQ(5)[8],=WP3ZA(5)[8], - =WP3ZP(5)[8],=WP4AIE(5)[8],=WP4AIL(5)[8],=WP4AIZ(5)[8],=WP4ALH(5)[8],=WP4AQK(5)[8],=WP4B(5)[8], - =WP4BFP(5)[8],=WP4BGM(5)[8],=WP4BIN(5)[8],=WP4BJS(5)[8],=WP4BK(5)[8],=WP4BQV(5)[8],=WP4BXS(5)[8], - =WP4CKW(5)[8],=WP4CLS(5)[8],=WP4CMH(5)[8],=WP4DC(5)[8],=WP4DCB(5)[8],=WP4DFK(5)[8],=WP4DNE(5)[8], - =WP4DPX(5)[8],=WP4ENX(5)[8],=WP4EXH(5)[8],=WP4FEI(5)[8],=WP4FRK(5)[8],=WP4FS(5)[8],=WP4GAK(5)[8], - =WP4GFH(5)[8],=WP4GX(5)[8],=WP4GYA(5)[8],=WP4HFZ(5)[8],=WP4HNN(5)[8],=WP4HOX(5)[8],=WP4IF(5)[8], - =WP4IJ(5)[8],=WP4JKO(5)[8],=WP4JQJ(5)[8],=WP4JSR(5)[8],=WP4JT(5)[8],=WP4KCJ(5)[8],=WP4KDH(5)[8], - =WP4KFP(5)[8],=WP4KGI(5)[8],=WP4KI(5)[8],=WP4KJV(5)[8],=WP4KSK(5)[8],=WP4KTD(5)[8],=WP4LBK(5)[8], - =WP4LDG(5)[8],=WP4LDL(5)[8],=WP4LDP(5)[8],=WP4LHA(5)[8],=WP4MAE(5)[8],=WP4MD(5)[8],=WP4MO(5)[8], - =WP4MQF(5)[8],=WP4MWE(5)[8],=WP4MXE(5)[8],=WP4MYG(5)[8],=WP4MYK(5)[8],=WP4NAI(5)[8],=WP4NAQ(5)[8], - =WP4NBF(5)[8],=WP4NBG(5)[8],=WP4NFU(5)[8],=WP4NKU(5)[8],=WP4NLQ(5)[8],=WP4NQA(5)[8],=WP4NVL(5)[8], - =WP4NWW(5)[8],=WP4O/4(5)[8],=WP4O/M(5)[8],=WP4ODR(5)[8],=WP4OFA(5)[8],=WP4OLM(5)[8],=WP4OMG(5)[8], - =WP4OMV(5)[8],=WP4ONR(5)[8],=WP4OOI(5)[8],=WP4OPD(5)[8],=WP4OPF(5)[8],=WP4OPG(5)[8],=WP4OTP(5)[8], - =WP4P(5)[8],=WP4PR(5)[8],=WP4PUV(5)[8],=WP4PWV(5)[8],=WP4PXG(5)[8],=WP4QHU(5)[8],=WP4SW(5)[8], - =WP4TD(5)[8],=WP4TX(5)[8],=WP4UM(5)[8], + =WP2MA(5)[8],=WP2P(5)[8],=WP3AY(5)[8],=WP3BC(5)[8],=WP3JE(5)[8],=WP3JQ(5)[8],=WP3JU(5)[8], + =WP3K(5)[8],=WP3LE(5)[8],=WP3MB(5)[8],=WP3ME(5)[8],=WP3NIS(5)[8],=WP3O(5)[8],=WP3ZA(5)[8], + =WP3ZP(5)[8],=WP4AIE(5)[8],=WP4AIL(5)[8],=WP4AIZ(5)[8],=WP4ALH(5)[8],=WP4AQK(5)[8],=WP4AVW(5)[8], + =WP4B(5)[8],=WP4BFP(5)[8],=WP4BGM(5)[8],=WP4BIN(5)[8],=WP4BJS(5)[8],=WP4BK(5)[8],=WP4BOC(5)[8], + =WP4BQV(5)[8],=WP4BXS(5)[8],=WP4CKW(5)[8],=WP4CLS(5)[8],=WP4CMH(5)[8],=WP4DC(5)[8],=WP4DCB(5)[8], + =WP4DFK(5)[8],=WP4DNE(5)[8],=WP4DPX(5)[8],=WP4ENX(5)[8],=WP4EXH(5)[8],=WP4FEI(5)[8],=WP4FRK(5)[8], + =WP4FS(5)[8],=WP4GAK(5)[8],=WP4GFH(5)[8],=WP4GX(5)[8],=WP4GYA(5)[8],=WP4HFZ(5)[8],=WP4HNN(5)[8], + =WP4HOX(5)[8],=WP4IF(5)[8],=WP4IJ(5)[8],=WP4ILP(5)[8],=WP4JKO(5)[8],=WP4JQJ(5)[8],=WP4JSR(5)[8], + =WP4JT(5)[8],=WP4KCJ(5)[8],=WP4KDH(5)[8],=WP4KFP(5)[8],=WP4KGI(5)[8],=WP4KI(5)[8],=WP4KJV(5)[8], + =WP4KSK(5)[8],=WP4KTD(5)[8],=WP4LBK(5)[8],=WP4LDG(5)[8],=WP4LDL(5)[8],=WP4LDP(5)[8],=WP4LHA(5)[8], + =WP4MAE(5)[8],=WP4MD(5)[8],=WP4MO(5)[8],=WP4MQF(5)[8],=WP4MWE(5)[8],=WP4MXE(5)[8],=WP4MYG(5)[8], + =WP4MYK(5)[8],=WP4NAI(5)[8],=WP4NAQ(5)[8],=WP4NBF(5)[8],=WP4NBG(5)[8],=WP4NFU(5)[8],=WP4NKU(5)[8], + =WP4NLQ(5)[8],=WP4NQA(5)[8],=WP4NVL(5)[8],=WP4NWW(5)[8],=WP4O/4(5)[8],=WP4O/M(5)[8],=WP4ODR(5)[8], + =WP4OFA(5)[8],=WP4OHJ(5)[8],=WP4OLM(5)[8],=WP4OMG(5)[8],=WP4OMV(5)[8],=WP4ONR(5)[8],=WP4OOI(5)[8], + =WP4OPD(5)[8],=WP4OPF(5)[8],=WP4OPG(5)[8],=WP4OTP(5)[8],=WP4OXA(5)[8],=WP4P(5)[8],=WP4PR(5)[8], + =WP4PUV(5)[8],=WP4PWV(5)[8],=WP4PXG(5)[8],=WP4QHU(5)[8],=WP4SW(5)[8],=WP4TD(5)[8],=WP4TX(5)[8], + =WP4UC(5)[8],=WP4UM(5)[8], AA5(4)[7],AB5(4)[7],AC5(4)[7],AD5(4)[7],AE5(4)[7],AF5(4)[7],AG5(4)[7],AI5(4)[7],AJ5(4)[7], AK5(4)[7],K5(4)[7],KA5(4)[7],KB5(4)[7],KC5(4)[7],KD5(4)[7],KE5(4)[7],KF5(4)[7],KG5(4)[7], KI5(4)[7],KJ5(4)[7],KK5(4)[7],KM5(4)[7],KN5(4)[7],KO5(4)[7],KQ5(4)[7],KR5(4)[7],KS5(4)[7], @@ -1309,48 +1327,50 @@ United States: 05: 08: NA: 37.53: 91.67: 5.0: K: NW5(4)[7],NX5(4)[7],NY5(4)[7],NZ5(4)[7],W5(4)[7],WA5(4)[7],WB5(4)[7],WC5(4)[7],WD5(4)[7], WE5(4)[7],WF5(4)[7],WG5(4)[7],WI5(4)[7],WJ5(4)[7],WK5(4)[7],WM5(4)[7],WN5(4)[7],WO5(4)[7], WQ5(4)[7],WR5(4)[7],WS5(4)[7],WT5(4)[7],WU5(4)[7],WV5(4)[7],WW5(4)[7],WX5(4)[7],WY5(4)[7], - WZ5(4)[7],=AH2AQ(4)[7],=AH2AQ/5(4)[7],=AH2DG(4)[7],=AH2EH(4)[7],=AH2H(4)[7],=AH2T(4)[7], - =AH6AF(4)[7],=AH6DZ(4)[7],=AH6FV(4)[7],=AH6HT(4)[7],=AH6OU(4)[7],=AH6RB(4)[7],=AH6TD(4)[7], - =AH6UD(4)[7],=AH8O(4)[7],=AH9B(4)[7],=AL2K(4)[7],=AL2S(4)[7],=AL4F(4)[7],=AL5J(4)[7],=AL7C(4)[7], - =AL7CJ(4)[7],=AL7CQ(4)[7],=AL7DF(4)[7],=AL7DR(4)[7],=AL7GY(4)[7],=AL7HH(4)[7],=AL7HU(4)[7], - =AL7II/5(4)[7],=AL7IM(4)[7],=AL7J(4)[7],=AL7JP(4)[7],=AL7L/5(4)[7],=AL7PB(4)[7],=AL7RD(4)[7], - =AL7RI(4)[7],=KH0BZ(4)[7],=KH0CE(4)[7],=KH0CU(4)[7],=KH0DW(4)[7],=KH2AI(4)[7],=KH2BH(4)[7], - =KH2BI(4)[7],=KH2DF(4)[7],=KH2DF/5(4)[7],=KH2TB(4)[7],=KH2XD(4)[7],=KH2XO(4)[7],=KH2YO(4)[7], - =KH6ABA(4)[7],=KH6DAN(4)[7],=KH6GGC(4)[7],=KH6HPQ(4)[7],=KH6II(4)[7],=KH6ITY/M(4)[7], - =KH6JIQ(4)[7],=KH6JTM(4)[7],=KH6JVL(4)[7],=KH6KG/5(4)[7],=KH6LX(4)[7],=KH6MB/5(4)[7], - =KH6SP/5(4)[7],=KH6SZ(4)[7],=KH6UW(4)[7],=KH7CF(4)[7],=KH7FB(4)[7],=KH7IC(4)[7],=KH7JE(4)[7], - =KH7QL(4)[7],=KH7QO(4)[7],=KH8CG(4)[7],=KH9AE(4)[7],=KL0EX(4)[7],=KL0HU(4)[7],=KL0PG(4)[7], - =KL1DA(4)[7],=KL1DJ(4)[7],=KL1RX(4)[7],=KL1TS(4)[7],=KL1UR(4)[7],=KL1WG(4)[7],=KL1WO(4)[7], - =KL1XK(4)[7],=KL1Y(4)[7],=KL1ZW(4)[7],=KL2AX(4)[7],=KL2AX/5(4)[7],=KL2CD(4)[7],=KL2HC(4)[7], - =KL2HN(4)[7],=KL2MI(4)[7],=KL2NN(4)[7],=KL2RA(4)[7],=KL2RB(4)[7],=KL2TV(4)[7],=KL2VA(4)[7], - =KL3DB(4)[7],=KL3HK(4)[7],=KL3HZ(4)[7],=KL3JL(4)[7],=KL3KH(4)[7],=KL3KI(4)[7],=KL3TB(4)[7], - =KL4JQ(4)[7],=KL5L(4)[7],=KL5Z(4)[7],=KL7AH(4)[7],=KL7AU(4)[7],=KL7AX(4)[7],=KL7BCD(4)[7], - =KL7BL(4)[7],=KL7BX(4)[7],=KL7BZ/5(4)[7],=KL7BZL(4)[7],=KL7CD(4)[7],=KL7DB(4)[7],=KL7EBE(4)[7], - =KL7EMH(4)[7],=KL7EMH/M(4)[7],=KL7EQQ(4)[7],=KL7F(4)[7],=KL7FB(4)[7],=KL7FHX(4)[7],=KL7FLY(4)[7], - =KL7FQR(4)[7],=KL7GNW(4)[7],=KL7HH(4)[7],=KL7IDM(4)[7],=KL7IK(4)[7],=KL7ITF(4)[7],=KL7IWU(4)[7], - =KL7IZW(4)[7],=KL7JAR(4)[7],=KL7JEX(4)[7],=KL7JIU(4)[7],=KL7JR/5(4)[7],=KL7JW(4)[7],=KL7LJ(4)[7], - =KL7LY(4)[7],=KL7MA(4)[7],=KL7ME(4)[7],=KL7ML(4)[7],=KL7NE(4)[7],=KL7NI(4)[7],=KL7OI(4)[7], - =KL7PZ(4)[7],=KL7QC(4)[7],=KL7SG(4)[7],=KL7TN/5(4)[7],=KL7UHF(4)[7],=KL7USI/5(4)[7],=KL7XP(4)[7], - =KL7XS(4)[7],=KL7YY/5(4)[7],=KP2AZ(4)[7],=KP4CV(4)[7],=KP4DJT(4)[7],=KP4FF(4)[7],=KP4FFW(4)[7], - =KP4GMC(4)[7],=KP4JE(4)[7],=KP4JG(4)[7],=KP4JY(4)[7],=KP4YP(4)[7],=NH0V/5(4)[7],=NH2LA(4)[7], - =NH6AZ(4)[7],=NH6CJ(4)[7],=NH6EF(4)[7],=NH6FA(4)[7],=NH6L(4)[7],=NH6VB(4)[7],=NH6WL(4)[7], - =NH6WL/5(4)[7],=NH7FO(4)[7],=NH7MV(4)[7],=NH7PZ(4)[7],=NH7RO(4)[7],=NH7RO/5(4)[7],=NH7TR(4)[7], - =NH7VA(4)[7],=NL5J(4)[7],=NL7AX(4)[7],=NL7C(4)[7],=NL7CO(4)[7],=NL7CO/5(4)[7],=NL7CO/M(4)[7], - =NL7DC(4)[7],=NL7HB(4)[7],=NL7IE(4)[7],=NL7JH(4)[7],=NL7JI(4)[7],=NL7K/5(4)[7],=NL7KB(4)[7], - =NL7NP(4)[7],=NL7PD(4)[7],=NL7RQ(4)[7],=NL7RQ/5(4)[7],=NL7TO(4)[7],=NL7ZL(4)[7],=NP2EE(4)[7], - =NP2PR(4)[7],=NP2RA(4)[7],=NP3BA(4)[7],=NP3CV(4)[7],=NP3NT(4)[7],=NP3PG(4)[7],=NP3RG(4)[7], - =NP3SU(4)[7],=NP3TY(4)[7],=NP4EA(4)[7],=NP4NQ(4)[7],=NP4NQ/5(4)[7],=NP4RW(4)[7],=NP4RZ(4)[7], - =WH2ACT(4)[7],=WH2ACT/5(4)[7],=WH6ARN(4)[7],=WH6BYP(4)[7],=WH6CDU(4)[7],=WH6CUL(4)[7], - =WH6DZU(4)[7],=WH6ECJ(4)[7],=WH6EMW(4)[7],=WH6EOF(4)[7],=WH6ERS(4)[7],=WH6EUA(4)[7],=WH6EXQ(4)[7], - =WH6FAD(4)[7],=WH6FGM(4)[7],=WH6FZ/5(4)[7],=WH6L/5(4)[7],=WH6ZR(4)[7],=WH7DC(4)[7],=WH7DW(4)[7], - =WH7OK(4)[7],=WH7R(4)[7],=WH7YQ(4)[7],=WH7YR(4)[7],=WL3WX(4)[7],=WL5H(4)[7],=WL7AIU(4)[7], - =WL7AWC(4)[7],=WL7BBV(4)[7],=WL7BKF(4)[7],=WL7BPY(4)[7],=WL7CA(4)[7],=WL7CJA(4)[7],=WL7CJC(4)[7], - =WL7CQE(4)[7],=WL7CTP(4)[7],=WL7CTQ(4)[7],=WL7D(4)[7],=WL7FT(4)[7],=WL7FT/5(4)[7],=WL7K/5(4)[7], - =WL7ME(4)[7],=WL7MQ/5(4)[7],=WL7OP(4)[7],=WL7OU(4)[7],=WL7SG(4)[7],=WL7W(4)[7],=WL7XI(4)[7], - =WL7XR(4)[7],=WP2AHG(4)[7],=WP2WP(4)[7],=WP3AL(4)[7],=WP4A(4)[7],=WP4APJ(4)[7],=WP4BAB(4)[7], - =WP4BAT(4)[7],=WP4CJY(4)[7],=WP4EVA(4)[7],=WP4EVL(4)[7],=WP4KSP(4)[7],=WP4KTF(4)[7],=WP4KUW(4)[7], - =WP4LKA(4)[7],=WP4MJP(4)[7],=WP4MWS(4)[7],=WP4MYI(4)[7],=WP4MZR(4)[7],=WP4NAK(4)[7],=WP4NEP(4)[7], - =WP4NQL(4)[7],=WP4OUE(4)[7],=WP4RON(4)[7], + WZ5(4)[7],=AH2AQ(4)[7],=AH2AQ/5(4)[7],=AH2DG(4)[7],=AH2DR(4)[7],=AH2EH(4)[7],=AH2H(4)[7], + =AH2T(4)[7],=AH6AF(4)[7],=AH6DZ(4)[7],=AH6FV(4)[7],=AH6HT(4)[7],=AH6OU(4)[7],=AH6RB(4)[7], + =AH6TD(4)[7],=AH6UD(4)[7],=AH8O(4)[7],=AH9B(4)[7],=AL1F(4)[7],=AL2K(4)[7],=AL2S(4)[7],=AL4F(4)[7], + =AL5J(4)[7],=AL7C(4)[7],=AL7CJ(4)[7],=AL7CQ(4)[7],=AL7DF(4)[7],=AL7DR(4)[7],=AL7GY(4)[7], + =AL7HH(4)[7],=AL7HU(4)[7],=AL7IH(4)[7],=AL7II/5(4)[7],=AL7IM(4)[7],=AL7J(4)[7],=AL7JP(4)[7], + =AL7L/5(4)[7],=AL7PB(4)[7],=AL7RD(4)[7],=AL7RI(4)[7],=AL7V(4)[7],=KH0BZ(4)[7],=KH0CE(4)[7], + =KH0CU(4)[7],=KH0DW(4)[7],=KH2AI(4)[7],=KH2BH(4)[7],=KH2DF(4)[7],=KH2DF/5(4)[7],=KH2TB(4)[7], + =KH2XD(4)[7],=KH2XO(4)[7],=KH2YO(4)[7],=KH6ABA(4)[7],=KH6DAN(4)[7],=KH6GGC(4)[7],=KH6HPQ(4)[7], + =KH6II(4)[7],=KH6ITY/M(4)[7],=KH6JIQ(4)[7],=KH6JTM(4)[7],=KH6JVL(4)[7],=KH6KG/5(4)[7], + =KH6LL(4)[7],=KH6LX(4)[7],=KH6MB/5(4)[7],=KH6SP/5(4)[7],=KH6SZ(4)[7],=KH6UW(4)[7],=KH7CF(4)[7], + =KH7FB(4)[7],=KH7IC(4)[7],=KH7JE(4)[7],=KH7QL(4)[7],=KH7QO(4)[7],=KH8CG(4)[7],=KH9AE(4)[7], + =KL0EX(4)[7],=KL0HU(4)[7],=KL0PG(4)[7],=KL1DA(4)[7],=KL1DJ(4)[7],=KL1MM(4)[7],=KL1RX(4)[7], + =KL1TS(4)[7],=KL1UR(4)[7],=KL1WG(4)[7],=KL1WO(4)[7],=KL1XK(4)[7],=KL1Y(4)[7],=KL1ZW(4)[7], + =KL2AX(4)[7],=KL2AX/5(4)[7],=KL2CD(4)[7],=KL2HC(4)[7],=KL2HN(4)[7],=KL2MI(4)[7],=KL2RA(4)[7], + =KL2RB(4)[7],=KL2TV(4)[7],=KL2VA(4)[7],=KL3DB(4)[7],=KL3DP(4)[7],=KL3HK(4)[7],=KL3HZ(4)[7], + =KL3JL(4)[7],=KL3KH(4)[7],=KL3KI(4)[7],=KL3TB(4)[7],=KL4JQ(4)[7],=KL5L(4)[7],=KL5Z(4)[7], + =KL7AH(4)[7],=KL7AU(4)[7],=KL7AX(4)[7],=KL7BCD(4)[7],=KL7BL(4)[7],=KL7BX(4)[7],=KL7BZ/5(4)[7], + =KL7BZL(4)[7],=KL7CD(4)[7],=KL7DB(4)[7],=KL7EBE(4)[7],=KL7EMH(4)[7],=KL7EMH/M(4)[7],=KL7EQQ(4)[7], + =KL7F(4)[7],=KL7FB(4)[7],=KL7FHX(4)[7],=KL7FLY(4)[7],=KL7FQR(4)[7],=KL7GNW(4)[7],=KL7HH(4)[7], + =KL7HJZ(4)[7],=KL7IDM(4)[7],=KL7IK(4)[7],=KL7ITF(4)[7],=KL7IWU(4)[7],=KL7IZW(4)[7],=KL7JAR(4)[7], + =KL7JEX(4)[7],=KL7JIU(4)[7],=KL7JR/5(4)[7],=KL7JW(4)[7],=KL7LJ(4)[7],=KL7LY(4)[7],=KL7MA(4)[7], + =KL7ME(4)[7],=KL7ML(4)[7],=KL7NE(4)[7],=KL7NI(4)[7],=KL7OI(4)[7],=KL7PZ(4)[7],=KL7QC(4)[7], + =KL7SG(4)[7],=KL7TN/5(4)[7],=KL7UHF(4)[7],=KL7USI/5(4)[7],=KL7XP(4)[7],=KL7XS(4)[7], + =KL7YY/5(4)[7],=KP2AZ(4)[7],=KP4CV(4)[7],=KP4DJT(4)[7],=KP4FF(4)[7],=KP4FFW(4)[7],=KP4GMC(4)[7], + =KP4JE(4)[7],=KP4JG(4)[7],=KP4JY(4)[7],=KP4YP(4)[7],=NH0V/5(4)[7],=NH2LP(4)[7],=NH6AZ(4)[7], + =NH6CJ(4)[7],=NH6EF(4)[7],=NH6FA(4)[7],=NH6L(4)[7],=NH6MG(4)[7],=NH6VB(4)[7],=NH6VJ(4)[7], + =NH6WL(4)[7],=NH6WL/5(4)[7],=NH7FO(4)[7],=NH7MV(4)[7],=NH7PZ(4)[7],=NH7R(4)[7],=NH7RO(4)[7], + =NH7RO/5(4)[7],=NH7TR(4)[7],=NH7VA(4)[7],=NL5J(4)[7],=NL7AX(4)[7],=NL7C(4)[7],=NL7CO(4)[7], + =NL7CO/5(4)[7],=NL7CO/M(4)[7],=NL7DC(4)[7],=NL7HB(4)[7],=NL7IE(4)[7],=NL7JH(4)[7],=NL7JI(4)[7], + =NL7K/5(4)[7],=NL7KB(4)[7],=NL7NP(4)[7],=NL7OM(4)[7],=NL7PD(4)[7],=NL7RQ(4)[7],=NL7RQ/5(4)[7], + =NL7SI(4)[7],=NL7TO(4)[7],=NL7ZL(4)[7],=NP2EE(4)[7],=NP2PR(4)[7],=NP2RA(4)[7],=NP3BA(4)[7], + =NP3CV(4)[7],=NP3NT(4)[7],=NP3PG(4)[7],=NP3RG(4)[7],=NP3SU(4)[7],=NP3TY(4)[7],=NP4EA(4)[7], + =NP4NQ(4)[7],=NP4NQ/5(4)[7],=NP4RW(4)[7],=NP4RZ(4)[7],=WH2ACT(4)[7],=WH2ACT/5(4)[7],=WH6ARN(4)[7], + =WH6BYJ(4)[7],=WH6BYP(4)[7],=WH6CDU(4)[7],=WH6CUL(4)[7],=WH6DZU(4)[7],=WH6ECJ(4)[7],=WH6EMW(4)[7], + =WH6EOF(4)[7],=WH6ERS(4)[7],=WH6EUA(4)[7],=WH6EXQ(4)[7],=WH6FAD(4)[7],=WH6FGM(4)[7], + =WH6FZ/5(4)[7],=WH6L/5(4)[7],=WH7DC(4)[7],=WH7DW(4)[7],=WH7OK(4)[7],=WH7R(4)[7],=WH7YQ(4)[7], + =WH7YR(4)[7],=WL3WX(4)[7],=WL5H(4)[7],=WL7AIU(4)[7],=WL7AWC(4)[7],=WL7BBV(4)[7],=WL7BKF(4)[7], + =WL7BPY(4)[7],=WL7CA(4)[7],=WL7CJA(4)[7],=WL7CJC(4)[7],=WL7CQE(4)[7],=WL7CTP(4)[7],=WL7CTQ(4)[7], + =WL7D(4)[7],=WL7FE(4)[7],=WL7FT(4)[7],=WL7FT/5(4)[7],=WL7K/5(4)[7],=WL7ME(4)[7],=WL7MQ/5(4)[7], + =WL7OP(4)[7],=WL7OU(4)[7],=WL7SG(4)[7],=WL7W(4)[7],=WL7XI(4)[7],=WL7XR(4)[7],=WP2AHG(4)[7], + =WP2WP(4)[7],=WP3AL(4)[7],=WP4A(4)[7],=WP4ADA(4)[7],=WP4APJ(4)[7],=WP4BAB(4)[7],=WP4BAT(4)[7], + =WP4CJY(4)[7],=WP4EVA(4)[7],=WP4EVL(4)[7],=WP4KSP(4)[7],=WP4KTF(4)[7],=WP4KUW(4)[7],=WP4LKA(4)[7], + =WP4MJP(4)[7],=WP4MWS(4)[7],=WP4MYI(4)[7],=WP4MZR(4)[7],=WP4NAK(4)[7],=WP4NEP(4)[7],=WP4NQL(4)[7], + =WP4OUE(4)[7],=WP4RON(4)[7], AA6(3)[6],AB6(3)[6],AC6(3)[6],AD6(3)[6],AE6(3)[6],AF6(3)[6],AG6(3)[6],AI6(3)[6],AJ6(3)[6], AK6(3)[6],K6(3)[6],KA6(3)[6],KB6(3)[6],KC6(3)[6],KD6(3)[6],KE6(3)[6],KF6(3)[6],KG6(3)[6], KI6(3)[6],KJ6(3)[6],KK6(3)[6],KM6(3)[6],KN6(3)[6],KO6(3)[6],KQ6(3)[6],KR6(3)[6],KS6(3)[6], @@ -1360,53 +1380,56 @@ United States: 05: 08: NA: 37.53: 91.67: 5.0: K: NW6(3)[6],NX6(3)[6],NY6(3)[6],NZ6(3)[6],W6(3)[6],WA6(3)[6],WB6(3)[6],WC6(3)[6],WD6(3)[6], WE6(3)[6],WF6(3)[6],WG6(3)[6],WI6(3)[6],WJ6(3)[6],WK6(3)[6],WM6(3)[6],WN6(3)[6],WO6(3)[6], WQ6(3)[6],WR6(3)[6],WS6(3)[6],WT6(3)[6],WU6(3)[6],WV6(3)[6],WW6(3)[6],WX6(3)[6],WY6(3)[6], - WZ6(3)[6],=AH0CS(3)[6],=AH0FM(3)[6],=AH0U(3)[6],=AH0U/6(3)[6],=AH2AP(3)[6],=AH2DY(3)[6], + WZ6(3)[6],=AH0C(3)[6],=AH0CS(3)[6],=AH0U(3)[6],=AH0U/6(3)[6],=AH2AP(3)[6],=AH2DY(3)[6], =AH6BS(3)[6],=AH6CY(3)[6],=AH6CY/P(3)[6],=AH6EI(3)[6],=AH6HE(3)[6],=AH6KG(3)[6],=AH6ML(3)[6], =AH6NL(3)[6],=AH6NP(3)[6],=AH6PD(3)[6],=AH6RI(3)[6],=AH6S(3)[6],=AH6SU(3)[6],=AH6TX(3)[6], =AH6UN(3)[6],=AH7A(3)[6],=AH7D(3)[6],=AH7F(3)[6],=AH8C(3)[6],=AL3A(3)[6],=AL5ET(3)[6],=AL6A(3)[6], =AL7DQ(3)[6],=AL7EM(3)[6],=AL7EP(3)[6],=AL7EW(3)[6],=AL7FN(3)[6],=AL7GS(3)[6],=AL7HO/6(3)[6], - =AL7L/6(3)[6],=KH0BR(3)[6],=KH0BU(3)[6],=KH0CA(3)[6],=KH0CG(3)[6],=KH0DH(3)[6],=KH0DJ(3)[6], - =KH0HQ(3)[6],=KH0JJ(3)[6],=KH0UM(3)[6],=KH0V(3)[6],=KH2BD(3)[6],=KH2BR(3)[6],=KH2BR/6(3)[6], - =KH2C(3)[6],=KH2EE(3)[6],=KH2FI(3)[6],=KH2FI/6(3)[6],=KH2H(3)[6],=KH2IW(3)[6],=KH2LU(3)[6], - =KH2LW(3)[6],=KH2LZ(3)[6],=KH2OJ(3)[6],=KH2QE(3)[6],=KH2QL(3)[6],=KH2QY(3)[6],=KH2TJ(3)[6], - =KH2TJ/6(3)[6],=KH2XW(3)[6],=KH2YJ(3)[6],=KH2Z(3)[6],=KH2ZM(3)[6],=KH4AB(3)[6],=KH6AS(3)[6], - =KH6BMD(3)[6],=KH6BRY(3)[6],=KH6COL(3)[6],=KH6DDW(3)[6],=KH6DX/M(3)[6],=KH6DX/M6(3)[6], - =KH6DZ(3)[6],=KH6EHF(3)[6],=KH6FH(3)[6],=KH6FL(3)[6],=KH6FOX(3)[6],=KH6FQR(3)[6],=KH6FQY(3)[6], - =KH6GBQ(3)[6],=KH6GC(3)[6],=KH6GJV(3)[6],=KH6GJV/6(3)[6],=KH6GK(3)[6],=KH6GKR(3)[6],=KH6HJE(3)[6], - =KH6HOU(3)[6],=KH6IKH(3)[6],=KH6IKL(3)[6],=KH6IP(3)[6],=KH6IPJ(3)[6],=KH6JCT(3)[6],=KH6JGD(3)[6], - =KH6JJN(3)[6],=KH6JJN/P(3)[6],=KH6JN(3)[6],=KH6JRB(3)[6],=KH6JRC(3)[6],=KH6JS(3)[6],=KH6JUZ(3)[6], + =AL7L/6(3)[6],=AL7PS(3)[6],=AL7QR(3)[6],=KH0BR(3)[6],=KH0BU(3)[6],=KH0CA(3)[6],=KH0CG(3)[6], + =KH0DH(3)[6],=KH0DJ(3)[6],=KH0HQ(3)[6],=KH0JJ(3)[6],=KH0V(3)[6],=KH0XD(3)[6],=KH2BD(3)[6], + =KH2BI(3)[6],=KH2BR(3)[6],=KH2BR/6(3)[6],=KH2C(3)[6],=KH2EE(3)[6],=KH2FI(3)[6],=KH2FI/6(3)[6], + =KH2H(3)[6],=KH2IW(3)[6],=KH2LU(3)[6],=KH2LW(3)[6],=KH2LZ(3)[6],=KH2OJ(3)[6],=KH2QE(3)[6], + =KH2QL(3)[6],=KH2QY(3)[6],=KH2TJ(3)[6],=KH2TJ/6(3)[6],=KH2XW(3)[6],=KH2YJ(3)[6],=KH2Z(3)[6], + =KH2ZM(3)[6],=KH4AB(3)[6],=KH6ARA(3)[6],=KH6AS(3)[6],=KH6BMD(3)[6],=KH6BRY(3)[6],=KH6COL(3)[6], + =KH6DDW(3)[6],=KH6DX/M(3)[6],=KH6DX/M6(3)[6],=KH6DZ(3)[6],=KH6EHF(3)[6],=KH6FH(3)[6],=KH6FL(3)[6], + =KH6FOX(3)[6],=KH6FQR(3)[6],=KH6FQY(3)[6],=KH6GBQ(3)[6],=KH6GC(3)[6],=KH6GJV(3)[6], + =KH6GJV/6(3)[6],=KH6GK(3)[6],=KH6GKR(3)[6],=KH6HJE(3)[6],=KH6HOU(3)[6],=KH6IKH(3)[6], + =KH6IKL(3)[6],=KH6IP(3)[6],=KH6IPJ(3)[6],=KH6JCT(3)[6],=KH6JGD(3)[6],=KH6JJN(3)[6], + =KH6JJN/P(3)[6],=KH6JN(3)[6],=KH6JR(3)[6],=KH6JRB(3)[6],=KH6JRC(3)[6],=KH6JS(3)[6],=KH6JUZ(3)[6], =KH6JVS(3)[6],=KH6JWG(3)[6],=KH6KT(3)[6],=KH6LO(3)[6],=KH6MV(3)[6],=KH6N(3)[6],=KH6NG(3)[6], - =KH6PGA/6(3)[6],=KH6PM(3)[6],=KH6PW(3)[6],=KH6SC(3)[6],=KH6TO(3)[6],=KH6UQ(3)[6],=KH6USA(3)[6], - =KH6VC(3)[6],=KH6VC/6(3)[6],=KH6VZ(3)[6],=KH6WL(3)[6],=KH6WZ(3)[6],=KH7CD/6(3)[6],=KH7CO(3)[6], - =KH7CS(3)[6],=KH7EM(3)[6],=KH7I(3)[6],=KH7IZ(3)[6],=KH7JR(3)[6],=KH7NS(3)[6],=KH7QU(3)[6], - =KH7RB(3)[6],=KH7TJ(3)[6],=KH7TJ/6(3)[6],=KH7XX/6(3)[6],=KH7Y(3)[6],=KH7Y/6(3)[6],=KH8A(3)[6], - =KH8AF(3)[6],=KH8FL(3)[6],=KL0AA(3)[6],=KL0AF(3)[6],=KL0AL(3)[6],=KL0HZ(3)[6],=KL0IF(3)[6], - =KL1WE/6(3)[6],=KL2CQ(3)[6],=KL3JY/6(3)[6],=KL3YH(3)[6],=KL4GW(3)[6],=KL4LV(3)[6],=KL4NZ(3)[6], - =KL4QW(3)[6],=KL7AK(3)[6],=KL7CE/6(3)[6],=KL7CM(3)[6],=KL7CN(3)[6],=KL7CW/6(3)[6],=KL7CX(3)[6], + =KH6O(3)[6],=KH6PGA/6(3)[6],=KH6PM(3)[6],=KH6PW(3)[6],=KH6SC(3)[6],=KH6TO(3)[6],=KH6UQ(3)[6], + =KH6USA(3)[6],=KH6VC(3)[6],=KH6VC/6(3)[6],=KH6VZ(3)[6],=KH6WL(3)[6],=KH6WZ(3)[6],=KH7CD/6(3)[6], + =KH7CO(3)[6],=KH7CS(3)[6],=KH7EM(3)[6],=KH7I(3)[6],=KH7IZ(3)[6],=KH7JR(3)[6],=KH7NS(3)[6], + =KH7QS(3)[6],=KH7QU(3)[6],=KH7RB(3)[6],=KH7TJ(3)[6],=KH7TJ/6(3)[6],=KH7TR(3)[6],=KH7TW(3)[6], + =KH7XX/6(3)[6],=KH7Y(3)[6],=KH7Y/6(3)[6],=KH8A(3)[6],=KH8AF(3)[6],=KH8FL(3)[6],=KL0AA(3)[6], + =KL0AF(3)[6],=KL0AL(3)[6],=KL0HZ(3)[6],=KL0IF(3)[6],=KL1NER(3)[6],=KL1WE/6(3)[6],=KL2CQ(3)[6], + =KL3IM(3)[6],=KL3JY/6(3)[6],=KL3YH(3)[6],=KL4GW(3)[6],=KL4LV(3)[6],=KL4NZ(3)[6],=KL4QW(3)[6], + =KL4UZ(3)[6],=KL7AK(3)[6],=KL7CE/6(3)[6],=KL7CM(3)[6],=KL7CN(3)[6],=KL7CW/6(3)[6],=KL7CX(3)[6], =KL7DJ(3)[6],=KL7EAE(3)[6],=KL7EAL(3)[6],=KL7HQR(3)[6],=KL7HQR/6(3)[6],=KL7HSY(3)[6],=KL7ID(3)[6], - =KL7IDY/6(3)[6],=KL7ISN(3)[6],=KL7JBE(3)[6],=KL7KNP(3)[6],=KL7KX(3)[6],=KL7MF(3)[6], + =KL7IDY/6(3)[6],=KL7ISB(3)[6],=KL7ISN(3)[6],=KL7JBE(3)[6],=KL7KNP(3)[6],=KL7KX(3)[6],=KL7MF(3)[6], =KL7MF/6(3)[6],=KL7MF/M(3)[6],=KL7OO(3)[6],=KL7RT(3)[6],=KL7SL(3)[6],=KL7SY(3)[6],=KL7VU(3)[6], =KL7VU/6(3)[6],=KP2BK(3)[6],=KP3BN(3)[6],=KP3YL(3)[6],=KP4BR(3)[6],=KP4DSO(3)[6],=KP4DX/6(3)[6], =KP4ENM(3)[6],=KP4ERR(3)[6],=KP4FBT(3)[6],=KP4MD(3)[6],=KP4UB(3)[6],=NH0C(3)[6],=NH0X(3)[6], =NH2AR(3)[6],=NH2BD(3)[6],=NH2BV(3)[6],=NH2CM(3)[6],=NH2FT(3)[6],=NH2FX(3)[6],=NH2R(3)[6], - =NH2S(3)[6],=NH6AC(3)[6],=NH6AE(3)[6],=NH6FV(3)[6],=NH6FX(3)[6],=NH6NG(3)[6],=NH6RG(3)[6], - =NH6WR(3)[6],=NH7AG(3)[6],=NH7EM(3)[6],=NH7FW(3)[6],=NH7G(3)[6],=NH7IG(3)[6],=NH7IH(3)[6], - =NH7PM(3)[6],=NH7QV(3)[6],=NH7RT(3)[6],=NH7ST(3)[6],=NH7SU(3)[6],=NH7WE(3)[6],=NH7WG(3)[6], - =NH7ZE(3)[6],=NL7GE(3)[6],=NL7IB(3)[6],=NL7OP(3)[6],=NL7RO(3)[6],=NL7YB(3)[6],=NP2KY(3)[6], - =NP4AI/6(3)[6],=NP4IW(3)[6],=NP4IW/6(3)[6],=NP4MV(3)[6],=NP4XE(3)[6],=WH0AAZ(3)[6],=WH0M(3)[6], - =WH2ABS(3)[6],=WH2ALN(3)[6],=WH6AAJ(3)[6],=WH6AFM(3)[6],=WH6ANA(3)[6],=WH6ASW/M(3)[6], - =WH6BYT(3)[6],=WH6CIL(3)[6],=WH6CK(3)[6],=WH6CO(3)[6],=WH6CPO(3)[6],=WH6CPT(3)[6],=WH6CRE(3)[6], - =WH6CSG(3)[6],=WH6CUF(3)[6],=WH6CUU(3)[6],=WH6CUX(3)[6],=WH6CVJ(3)[6],=WH6CWS(3)[6],=WH6CZF(3)[6], - =WH6CZH(3)[6],=WH6DHN(3)[6],=WH6DSK(3)[6],=WH6DVM(3)[6],=WH6DVN(3)[6],=WH6DVX(3)[6],=WH6DYA(3)[6], - =WH6DZV(3)[6],=WH6DZY(3)[6],=WH6EAR(3)[6],=WH6EEZ(3)[6],=WH6EHY(3)[6],=WH6EKB(3)[6],=WH6ENG(3)[6], - =WH6EUH(3)[6],=WH6EZW(3)[6],=WH6JO(3)[6],=WH6LZ(3)[6],=WH6OI(3)[6],=WH6PX(3)[6],=WH6QA(3)[6], - =WH6RF(3)[6],=WH6TD(3)[6],=WH6TK(3)[6],=WH6USA(3)[6],=WH6VM(3)[6],=WH6VN(3)[6],=WH6XI(3)[6], - =WH6XX(3)[6],=WH6YJ(3)[6],=WH7DG(3)[6],=WH7DH(3)[6],=WH7HQ(3)[6],=WH7IN(3)[6],=WH7IV(3)[6], - =WH7IZ(3)[6],=WH7LP(3)[6],=WH7OO(3)[6],=WH7PM(3)[6],=WH7QC(3)[6],=WH7RU(3)[6],=WH7TT(3)[6], - =WH7VM(3)[6],=WH7XR(3)[6],=WL3AF(3)[6],=WL3DZ(3)[6],=WL4JC(3)[6],=WL7ACO(3)[6],=WL7BA(3)[6], - =WL7BGF(3)[6],=WL7CPL(3)[6],=WL7CSD(3)[6],=WL7DN/6(3)[6],=WL7EA(3)[6],=WL7EKK(3)[6],=WL7RA(3)[6], - =WL7SE(3)[6],=WL7TG(3)[6],=WL7WL(3)[6],=WL7YQ(3)[6],=WL7YQ/6(3)[6],=WP2N(3)[6],=WP4CUJ(3)[6], - =WP4CW(3)[6],=WP4KSU(3)[6],=WP4MVE(3)[6], + =NH2S(3)[6],=NH6AC(3)[6],=NH6AE(3)[6],=NH6AF(3)[6],=NH6FV(3)[6],=NH6FX(3)[6],=NH6NG(3)[6], + =NH6RG(3)[6],=NH6ST(3)[6],=NH6WR(3)[6],=NH7AG(3)[6],=NH7EM(3)[6],=NH7FW(3)[6],=NH7G(3)[6], + =NH7IG(3)[6],=NH7IH(3)[6],=NH7PM(3)[6],=NH7QV(3)[6],=NH7RT(3)[6],=NH7ST(3)[6],=NH7SU(3)[6], + =NH7WE(3)[6],=NH7WG(3)[6],=NH7ZE(3)[6],=NL7GE(3)[6],=NL7IB(3)[6],=NL7LC(3)[6],=NL7OP(3)[6], + =NL7RO(3)[6],=NL7YB(3)[6],=NP2KY(3)[6],=NP4AB(3)[6],=NP4AI/6(3)[6],=NP4IW(3)[6],=NP4IW/6(3)[6], + =NP4MV(3)[6],=NP4XE(3)[6],=WH0AAZ(3)[6],=WH0M(3)[6],=WH2ABS(3)[6],=WH2ALN(3)[6],=WH2K(3)[6], + =WH6AAJ(3)[6],=WH6AFM(3)[6],=WH6ANA(3)[6],=WH6ASW/M(3)[6],=WH6BYT(3)[6],=WH6CIL(3)[6], + =WH6CK(3)[6],=WH6CO(3)[6],=WH6CPO(3)[6],=WH6CPT(3)[6],=WH6CRE(3)[6],=WH6CSG(3)[6],=WH6CUF(3)[6], + =WH6CUU(3)[6],=WH6CUX(3)[6],=WH6CVJ(3)[6],=WH6CWS(3)[6],=WH6CZF(3)[6],=WH6CZH(3)[6],=WH6DHN(3)[6], + =WH6DSK(3)[6],=WH6DVM(3)[6],=WH6DVN(3)[6],=WH6DVX(3)[6],=WH6DYA(3)[6],=WH6DZV(3)[6],=WH6DZY(3)[6], + =WH6EAR(3)[6],=WH6EEZ(3)[6],=WH6EHY(3)[6],=WH6EKB(3)[6],=WH6ENG(3)[6],=WH6EUH(3)[6],=WH6EZW(3)[6], + =WH6JO(3)[6],=WH6LZ(3)[6],=WH6MC(3)[6],=WH6OI(3)[6],=WH6PX(3)[6],=WH6QA(3)[6],=WH6RF(3)[6], + =WH6TD(3)[6],=WH6TK(3)[6],=WH6USA(3)[6],=WH6VM(3)[6],=WH6VN(3)[6],=WH6XI(3)[6],=WH6XX(3)[6], + =WH6YJ(3)[6],=WH7DG(3)[6],=WH7DH(3)[6],=WH7HQ(3)[6],=WH7IN(3)[6],=WH7IV(3)[6],=WH7IZ(3)[6], + =WH7LP(3)[6],=WH7OO(3)[6],=WH7PM(3)[6],=WH7QC(3)[6],=WH7RU(3)[6],=WH7TT(3)[6],=WH7VM(3)[6], + =WH7XR(3)[6],=WL3AF(3)[6],=WL3DZ(3)[6],=WL4JC(3)[6],=WL7ACO(3)[6],=WL7BA(3)[6],=WL7BGF(3)[6], + =WL7CPL(3)[6],=WL7CSD(3)[6],=WL7DN/6(3)[6],=WL7EA(3)[6],=WL7EKK(3)[6],=WL7RA(3)[6],=WL7SE(3)[6], + =WL7TG(3)[6],=WL7WL(3)[6],=WL7YQ(3)[6],=WL7YQ/6(3)[6],=WP2N(3)[6],=WP4CUJ(3)[6],=WP4CW(3)[6], + =WP4KSU(3)[6],=WP4MVE(3)[6],=WP4OBB(3)[6], AA7(3)[6],AB7(3)[6],AC7(3)[6],AD7(3)[6],AE7(3)[6],AF7(3)[6],AG7(3)[6],AI7(3)[6],AJ7(3)[6], AK7(3)[6],K7(3)[6],KA7(3)[6],KB7(3)[6],KC7(3)[6],KD7(3)[6],KE7(3)[6],KF7(3)[6],KG7(3)[6], KI7(3)[6],KJ7(3)[6],KK7(3)[6],KM7(3)[6],KN7(3)[6],KO7(3)[6],KQ7(3)[6],KR7(3)[6],KS7(3)[6], @@ -1420,98 +1443,102 @@ United States: 05: 08: NA: 37.53: 91.67: 5.0: K: =AH2DP(3)[6],=AH2DS(3)[6],=AH2S(3)[6],=AH6B/7(3)[6],=AH6D(3)[6],=AH6ET(3)[6],=AH6EZ(3)[6], =AH6EZ/7(3)[6],=AH6FC/7(3)[6],=AH6GA(3)[6],=AH6HK(3)[6],=AH6HS(3)[6],=AH6HX(3)[6],=AH6I(3)[6], =AH6IP(3)[6],=AH6LE(3)[6],=AH6LE/7(3)[6],=AH6NJ(3)[6],=AH6NR(3)[6],=AH6OD(3)[6],=AH6PJ(3)[6], - =AH6QW(3)[6],=AH6RI/7(3)[6],=AH6SV(3)[6],=AH6VM(3)[6],=AH6VP(3)[6],=AH6Y(3)[6],=AH7MP(3)[6], - =AH8AC(3)[6],=AH8DX(3)[6],=AH8K(3)[6],=AH9A(3)[6],=AH9AC(3)[6],=AH9C(3)[6],=AL0AA(3)[6], - =AL0F(3)[6],=AL0FT(3)[6],=AL0H(3)[6],=AL0X(3)[6],=AL1N(3)[6],=AL1P(3)[6],=AL1VE(3)[6], - =AL1VE/R(3)[6],=AL2B(3)[6],=AL2N(3)[6],=AL3L(3)[6],=AL4Q/7(3)[6],=AL5B(3)[6],=AL5W(3)[6], + =AH6PW(3)[6],=AH6QW(3)[6],=AH6RI/7(3)[6],=AH6SV(3)[6],=AH6VM(3)[6],=AH6VP(3)[6],=AH6Y(3)[6], + =AH7MP(3)[6],=AH8AC(3)[6],=AH8DX(3)[6],=AH8K(3)[6],=AH9A(3)[6],=AH9AC(3)[6],=AH9C(3)[6], + =AL0AA(3)[6],=AL0F(3)[6],=AL0FT(3)[6],=AL0H(3)[6],=AL0X(3)[6],=AL1N(3)[6],=AL1P(3)[6], + =AL1VE(3)[6],=AL2B(3)[6],=AL2N(3)[6],=AL3L(3)[6],=AL4Q/7(3)[6],=AL5B(3)[6],=AL5W(3)[6], =AL7A(3)[6],=AL7AA(3)[6],=AL7AN(3)[6],=AL7AW(3)[6],=AL7BN(3)[6],=AL7BQ(3)[6],=AL7CC(3)[6], - =AL7CG(3)[6],=AL7CM/7(3)[6],=AL7CR(3)[6],=AL7CS(3)[6],=AL7D(3)[6],=AL7D/7(3)[6],=AL7D/P(3)[6], - =AL7D/R(3)[6],=AL7DD(3)[6],=AL7DU(3)[6],=AL7EI(3)[6],=AL7FA(3)[6],=AL7FB(3)[6],=AL7HS(3)[6], - =AL7HY(3)[6],=AL7IG(3)[6],=AL7IT(3)[6],=AL7JF(3)[6],=AL7JJ(3)[6],=AL7JS(3)[6],=AL7JW(3)[6], - =AL7JY(3)[6],=AL7KE(3)[6],=AL7KF(3)[6],=AL7KG(3)[6],=AL7KK(3)[6],=AL7KL(3)[6],=AL7KV(3)[6], - =AL7L/7(3)[6],=AL7MH(3)[6],=AL7MQ(3)[6],=AL7ND(3)[6],=AL7NK(3)[6],=AL7NZ(3)[6],=AL7OK(3)[6], - =AL7OW(3)[6],=AL7PR(3)[6],=AL7PV(3)[6],=AL7QL(3)[6],=AL7R(3)[6],=AL7R/7(3)[6],=AL7RF(3)[6], - =AL7RF/7(3)[6],=AL7RM(3)[6],=AL7RR(3)[6],=AL7W(3)[6],=G4KHG/M(3)[6],=KH0AS(3)[6],=KH0H(3)[6], - =KH0K(3)[6],=KH0SH(3)[6],=KH0TL(3)[6],=KH0X(3)[6],=KH2CH(3)[6],=KH2G(3)[6],=KH2GG(3)[6], - =KH2JA(3)[6],=KH2QH(3)[6],=KH2RK(3)[6],=KH2SK(3)[6],=KH2SR(3)[6],=KH2TJ/7(3)[6],=KH2TJ/P(3)[6], - =KH2XP(3)[6],=KH2YL(3)[6],=KH3AD(3)[6],=KH6AB(3)[6],=KH6AHQ(3)[6],=KH6BXZ(3)[6],=KH6CN(3)[6], - =KH6CN/7(3)[6],=KH6COY(3)[6],=KH6CQG(3)[6],=KH6CQH(3)[6],=KH6CQH/7(3)[6],=KH6DB(3)[6], - =KH6DE(3)[6],=KH6DOT(3)[6],=KH6DUT(3)[6],=KH6EE(3)[6],=KH6EE/7(3)[6],=KH6FKA/7(3)[6],=KH6GB(3)[6], - =KH6GDN(3)[6],=KH6HU(3)[6],=KH6HWK(3)[6],=KH6IA(3)[6],=KH6ICQ(3)[6],=KH6IKC(3)[6],=KH6IMN(3)[6], - =KH6IQX(3)[6],=KH6ITY(3)[6],=KH6JFL(3)[6],=KH6JIM/7(3)[6],=KH6JJS(3)[6],=KH6JPJ(3)[6], - =KH6JPO(3)[6],=KH6JRW(3)[6],=KH6JT(3)[6],=KH6JUQ(3)[6],=KH6KS(3)[6],=KH6KW(3)[6],=KH6LEM(3)[6], - =KH6ME(3)[6],=KH6MF(3)[6],=KH6NA(3)[6],=KH6NO/7(3)[6],=KH6NO/M(3)[6],=KH6NU(3)[6],=KH6OV(3)[6], - =KH6PG(3)[6],=KH6PR(3)[6],=KH6QAI(3)[6],=KH6QAI/7(3)[6],=KH6QAJ(3)[6],=KH6RW(3)[6],=KH6RY(3)[6], - =KH6SAT(3)[6],=KH6SS(3)[6],=KH6TG(3)[6],=KH6TX(3)[6],=KH6VM(3)[6],=KH6VM/7(3)[6],=KH6VT(3)[6], - =KH6WX(3)[6],=KH6XG(3)[6],=KH6XS(3)[6],=KH6XT(3)[6],=KH6YL(3)[6],=KH7AL(3)[6],=KH7AR(3)[6], - =KH7CB(3)[6],=KH7CM(3)[6],=KH7CZ(3)[6],=KH7FJ(3)[6],=KH7FR(3)[6],=KH7HH(3)[6],=KH7HWK(3)[6], - =KH7IP(3)[6],=KH7LE(3)[6],=KH7ME(3)[6],=KH7MR(3)[6],=KH7NP(3)[6],=KH7R(3)[6],=KH7SQ(3)[6], - =KH7SR(3)[6],=KH7WW(3)[6],=KH7WW/7(3)[6],=KH7X/7(3)[6],=KH7YD(3)[6],=KH7YD/7(3)[6],=KH8AB(3)[6], - =KH8AH(3)[6],=KH8AZ(3)[6],=KH8BG(3)[6],=KH8D(3)[6],=KH8E(3)[6],=KH8K(3)[6],=KH9AA(3)[6], - =KL0AI(3)[6],=KL0AN(3)[6],=KL0AP(3)[6],=KL0CA(3)[6],=KL0CM(3)[6],=KL0CW(3)[6],=KL0DF(3)[6], - =KL0DG(3)[6],=KL0DR(3)[6],=KL0DT(3)[6],=KL0IR(3)[6],=KL0IS(3)[6],=KL0IW(3)[6],=KL0IX(3)[6], - =KL0MO(3)[6],=KL0NM(3)[6],=KL0PP(3)[6],=KL0QD(3)[6],=KL0RA(3)[6],=KL0SZ(3)[6],=KL0TR(3)[6], + =AL7CG(3)[6],=AL7CM(3)[6],=AL7CM/7(3)[6],=AL7CR(3)[6],=AL7CS(3)[6],=AL7D(3)[6],=AL7D/7(3)[6], + =AL7D/P(3)[6],=AL7D/R(3)[6],=AL7DD(3)[6],=AL7DU(3)[6],=AL7EI(3)[6],=AL7EJ(3)[6],=AL7FA(3)[6], + =AL7FB(3)[6],=AL7HS(3)[6],=AL7HY(3)[6],=AL7IG(3)[6],=AL7IT(3)[6],=AL7JF(3)[6],=AL7JJ(3)[6], + =AL7JS(3)[6],=AL7JW(3)[6],=AL7JY(3)[6],=AL7KE(3)[6],=AL7KF(3)[6],=AL7KG(3)[6],=AL7KK(3)[6], + =AL7KL(3)[6],=AL7KV(3)[6],=AL7L/7(3)[6],=AL7LI(3)[6],=AL7LL(3)[6],=AL7MH(3)[6],=AL7MQ(3)[6], + =AL7ND(3)[6],=AL7NK(3)[6],=AL7NZ(3)[6],=AL7OK(3)[6],=AL7OW(3)[6],=AL7PR(3)[6],=AL7PV(3)[6], + =AL7QL(3)[6],=AL7R(3)[6],=AL7R/7(3)[6],=AL7RF(3)[6],=AL7RF/7(3)[6],=AL7RM(3)[6],=AL7RR(3)[6], + =AL7W(3)[6],=G4KHG/M(3)[6],=KH0AS(3)[6],=KH0H(3)[6],=KH0K(3)[6],=KH0SH(3)[6],=KH0TL(3)[6], + =KH0X(3)[6],=KH2CH(3)[6],=KH2G(3)[6],=KH2GG(3)[6],=KH2JA(3)[6],=KH2QH(3)[6],=KH2RK(3)[6], + =KH2SK(3)[6],=KH2SR(3)[6],=KH2TJ/7(3)[6],=KH2TJ/P(3)[6],=KH2XP(3)[6],=KH2YL(3)[6],=KH3AD(3)[6], + =KH6AB(3)[6],=KH6AHQ(3)[6],=KH6BXZ(3)[6],=KH6CN(3)[6],=KH6CN/7(3)[6],=KH6COY(3)[6],=KH6CQG(3)[6], + =KH6CQH(3)[6],=KH6CQH/7(3)[6],=KH6DB(3)[6],=KH6DE(3)[6],=KH6DOT(3)[6],=KH6DUT(3)[6],=KH6EE(3)[6], + =KH6EE/7(3)[6],=KH6FKA/7(3)[6],=KH6FU(3)[6],=KH6GB(3)[6],=KH6GDN(3)[6],=KH6HU(3)[6],=KH6HWK(3)[6], + =KH6IA(3)[6],=KH6ICQ(3)[6],=KH6IKC(3)[6],=KH6IMN(3)[6],=KH6IQX(3)[6],=KH6ITY(3)[6],=KH6JFL(3)[6], + =KH6JIM/7(3)[6],=KH6JJS(3)[6],=KH6JPJ(3)[6],=KH6JPO(3)[6],=KH6JRW(3)[6],=KH6JT(3)[6], + =KH6JUQ(3)[6],=KH6KS(3)[6],=KH6KW(3)[6],=KH6LEM(3)[6],=KH6ME(3)[6],=KH6MF(3)[6],=KH6NA(3)[6], + =KH6NO/7(3)[6],=KH6NO/M(3)[6],=KH6NU(3)[6],=KH6OV(3)[6],=KH6PG(3)[6],=KH6PR(3)[6],=KH6QAI(3)[6], + =KH6QAI/7(3)[6],=KH6QAJ(3)[6],=KH6RW(3)[6],=KH6RY(3)[6],=KH6SAT(3)[6],=KH6SS(3)[6],=KH6TG(3)[6], + =KH6TX(3)[6],=KH6VM(3)[6],=KH6VM/7(3)[6],=KH6VT(3)[6],=KH6WX(3)[6],=KH6XG(3)[6],=KH6XS(3)[6], + =KH6XT(3)[6],=KH6YL(3)[6],=KH7AL(3)[6],=KH7AR(3)[6],=KH7AX(3)[6],=KH7CB(3)[6],=KH7CM(3)[6], + =KH7CZ(3)[6],=KH7FJ(3)[6],=KH7FR(3)[6],=KH7HH(3)[6],=KH7HWK(3)[6],=KH7IP(3)[6],=KH7LE(3)[6], + =KH7ME(3)[6],=KH7MR(3)[6],=KH7NP(3)[6],=KH7R(3)[6],=KH7RD(3)[6],=KH7RT(3)[6],=KH7SQ(3)[6], + =KH7SR(3)[6],=KH7VB(3)[6],=KH7VC(3)[6],=KH7WW(3)[6],=KH7WW/7(3)[6],=KH7X/7(3)[6],=KH7YD(3)[6], + =KH7YD/7(3)[6],=KH8AB(3)[6],=KH8AH(3)[6],=KH8AZ(3)[6],=KH8BG(3)[6],=KH8D(3)[6],=KH8E(3)[6], + =KH8K(3)[6],=KH9AA(3)[6],=KL0AI(3)[6],=KL0AN(3)[6],=KL0AP(3)[6],=KL0CA(3)[6],=KL0CM(3)[6], + =KL0CW(3)[6],=KL0DF(3)[6],=KL0DG(3)[6],=KL0DR(3)[6],=KL0DT(3)[6],=KL0EU(3)[6],=KL0IR(3)[6], + =KL0IS(3)[6],=KL0IW(3)[6],=KL0IX(3)[6],=KL0LF(3)[6],=KL0MO(3)[6],=KL0NM(3)[6],=KL0NP(3)[6], + =KL0PC(3)[6],=KL0PP(3)[6],=KL0QD(3)[6],=KL0RA(3)[6],=KL0SA(3)[6],=KL0SZ(3)[6],=KL0TR(3)[6], =KL0TU(3)[6],=KL1AA(3)[6],=KL1AE(3)[6],=KL1DO(3)[6],=KL1DW(3)[6],=KL1ED(3)[6],=KL1JF(3)[6], =KL1K(3)[6],=KL1LE(3)[6],=KL1LZ(3)[6],=KL1MF(3)[6],=KL1OH(3)[6],=KL1QL(3)[6],=KL1RH(3)[6], =KL1RV(3)[6],=KL1SF/7(3)[6],=KL1SO(3)[6],=KL1U(3)[6],=KL1UA(3)[6],=KL1UM(3)[6],=KL1XI(3)[6], - =KL1YO(3)[6],=KL1YY/7(3)[6],=KL1ZG(3)[6],=KL1ZP(3)[6],=KL1ZR(3)[6],=KL2A/7(3)[6],=KL2BG(3)[6], + =KL1YO(3)[6],=KL1YY/7(3)[6],=KL1ZN(3)[6],=KL1ZP(3)[6],=KL1ZR(3)[6],=KL2A/7(3)[6],=KL2BG(3)[6], =KL2BO(3)[6],=KL2BW(3)[6],=KL2BY(3)[6],=KL2BZ(3)[6],=KL2FD(3)[6],=KL2FL(3)[6],=KL2JY(3)[6], - =KL2K(3)[6],=KL2KY(3)[6],=KL2LA(3)[6],=KL2LN(3)[6],=KL2LT(3)[6],=KL2MP(3)[6],=KL2NJ(3)[6], - =KL2NU(3)[6],=KL2NW(3)[6],=KL2OH(3)[6],=KL2OJ(3)[6],=KL2P(3)[6],=KL2QE(3)[6],=KL2VK(3)[6], - =KL2YH(3)[6],=KL3EZ(3)[6],=KL3FE(3)[6],=KL3IC(3)[6],=KL3IO(3)[6],=KL3IW(3)[6],=KL3MZ(3)[6], - =KL3NE(3)[6],=KL3NO(3)[6],=KL3OQ(3)[6],=KL3PD(3)[6],=KL3TW(3)[6],=KL3VJ(3)[6],=KL3XS(3)[6], - =KL4BS(3)[6],=KL4RKH(3)[6],=KL4YFD(3)[6],=KL7AB(3)[6],=KL7AD(3)[6],=KL7AW(3)[6],=KL7BD(3)[6], - =KL7BDC(3)[6],=KL7BH(3)[6],=KL7BR(3)[6],=KL7BS(3)[6],=KL7BT(3)[6],=KL7BUR(3)[6],=KL7BXP(3)[6], - =KL7C(3)[6],=KL7CPO(3)[6],=KL7CT(3)[6],=KL7DC(3)[6],=KL7DF(3)[6],=KL7DI(3)[6],=KL7DK(3)[6], - =KL7DLG(3)[6],=KL7EF(3)[6],=KL7EFL(3)[6],=KL7EH(3)[6],=KL7EIN(3)[6],=KL7EU(3)[6],=KL7FDQ(3)[6], - =KL7FDQ/7(3)[6],=KL7FOZ(3)[6],=KL7FRQ(3)[6],=KL7FS(3)[6],=KL7GA(3)[6],=KL7GCS(3)[6],=KL7GKY(3)[6], - =KL7GRF(3)[6],=KL7GT(3)[6],=KL7HB(3)[6],=KL7HBV(3)[6],=KL7HFI/7(3)[6],=KL7HFV(3)[6],=KL7HI(3)[6], - =KL7HJR(3)[6],=KL7HLF(3)[6],=KL7HM(3)[6],=KL7HMK(3)[6],=KL7HQL(3)[6],=KL7HSR(3)[6],=KL7IAL(3)[6], - =KL7IBT(3)[6],=KL7IDY(3)[6],=KL7IEI(3)[6],=KL7IFK(3)[6],=KL7IGB(3)[6],=KL7IHK(3)[6],=KL7IIK(3)[6], - =KL7IKV(3)[6],=KL7IL(3)[6],=KL7IME(3)[6],=KL7IPV(3)[6],=KL7ISE(3)[6],=KL7IUX(3)[6], - =KL7IWC/7(3)[6],=KL7IZC(3)[6],=KL7IZH(3)[6],=KL7JBB(3)[6],=KL7JDQ(3)[6],=KL7JES(3)[6], - =KL7JIJ(3)[6],=KL7JJE(3)[6],=KL7JKV(3)[6],=KL7KA(3)[6],=KL7KG/7(3)[6],=KL7LG(3)[6],=KL7LX(3)[6], - =KL7LZ(3)[6],=KL7M(3)[6],=KL7MY(3)[6],=KL7MZ(3)[6],=KL7NA(3)[6],=KL7NP(3)[6],=KL7NP/7(3)[6], - =KL7OA(3)[6],=KL7OF(3)[6],=KL7OL(3)[6],=KL7OR(3)[6],=KL7OR/7(3)[6],=KL7OS(3)[6],=KL7OY(3)[6], - =KL7PO(3)[6],=KL7QA(3)[6],=KL7QK(3)[6],=KL7QK/140(3)[6],=KL7QK/7(3)[6],=KL7QR(3)[6], - =KL7QR/7(3)[6],=KL7R(3)[6],=KL7RC(3)[6],=KL7RK(3)[6],=KL7RM(3)[6],=KL7RS(3)[6],=KL7S(3)[6], - =KL7SK(3)[6],=KL7SP(3)[6],=KL7T(3)[6],=KL7TU(3)[6],=KL7UP(3)[6],=KL7UT(3)[6],=KL7VK(3)[6], - =KL7VL(3)[6],=KL7VN(3)[6],=KL7VQ(3)[6],=KL7W(3)[6],=KL7WM(3)[6],=KL7WN(3)[6],=KL7WP(3)[6], - =KL7WP/7(3)[6],=KL7WT(3)[6],=KL7YJ(3)[6],=KL7YQ(3)[6],=KL7YY/M(3)[6],=KL7ZH(3)[6],=KL7ZW(3)[6], - =KL8RV(3)[6],=KL8SU(3)[6],=KL9PC(3)[6],=KP2BX(3)[6],=KP2CB(3)[6],=KP2CT(3)[6],=KP2X(3)[6], - =KP2Y(3)[6],=KP4BBN(3)[6],=KP4EFZ(3)[6],=KP4ND(3)[6],=KP4UZ(3)[6],=KP4X(3)[6],=NH0F(3)[6], - =NH0K(3)[6],=NH2DM(3)[6],=NH2JE(3)[6],=NH2KR(3)[6],=NH6B(3)[6],=NH6BF(3)[6],=NH6CI(3)[6], - =NH6DQ(3)[6],=NH6DX(3)[6],=NH6FF(3)[6],=NH6GZ(3)[6],=NH6HE(3)[6],=NH6HZ(3)[6],=NH6LM(3)[6], - =NH6NS(3)[6],=NH6U(3)[6],=NH6XP(3)[6],=NH6Z(3)[6],=NH6ZA(3)[6],=NH6ZE(3)[6],=NH7FZ(3)[6], - =NH7L(3)[6],=NH7M(3)[6],=NH7MY(3)[6],=NH7N(3)[6],=NH7ND(3)[6],=NH7NJ/7(3)[6],=NH7OC(3)[6], - =NH7PL(3)[6],=NH7RS(3)[6],=NH7S(3)[6],=NH7SH(3)[6],=NH7TG(3)[6],=NH7VZ(3)[6],=NH7W(3)[6], - =NH7WT(3)[6],=NH7WU(3)[6],=NH7YE(3)[6],=NH7YI(3)[6],=NL7AH(3)[6],=NL7AR(3)[6],=NL7AZ(3)[6], - =NL7CH(3)[6],=NL7D(3)[6],=NL7D/7(3)[6],=NL7DH(3)[6],=NL7DY(3)[6],=NL7EO(3)[6],=NL7FQ(3)[6], - =NL7FX(3)[6],=NL7GM(3)[6],=NL7GO(3)[6],=NL7GW(3)[6],=NL7HH(3)[6],=NL7HK(3)[6],=NL7HQ(3)[6], - =NL7HU(3)[6],=NL7IN(3)[6],=NL7JJ(3)[6],=NL7JN(3)[6],=NL7KV(3)[6],=NL7LI(3)[6],=NL7MS(3)[6], - =NL7MT(3)[6],=NL7NL(3)[6],=NL7OF(3)[6],=NL7PN(3)[6],=NL7QI(3)[6],=NL7RL(3)[6],=NL7TK(3)[6], - =NL7UE(3)[6],=NL7US(3)[6],=NL7WD(3)[6],=NL7WJ(3)[6],=NL7XX(3)[6],=NL7ZM(3)[6],=NL7ZN(3)[6], - =NL7ZP(3)[6],=NP2CT(3)[6],=NP2X/7(3)[6],=NP3PH(3)[6],=NP4AI/M(3)[6],=NP4ES(3)[6],=NP4FP(3)[6], - =NP4I(3)[6],=NP4JV(3)[6],=NP4JV/7(3)[6],=VA2GLB/P(3)[6],=WH0AAM(3)[6],=WH0J(3)[6],=WH2ACV(3)[6], - =WH2AJF(3)[6],=WH6ARU(3)[6],=WH6ASB(3)[6],=WH6B(3)[6],=WH6BDR(3)[6],=WH6BLM(3)[6],=WH6BPU(3)[6], - =WH6CF(3)[6],=WH6CMS(3)[6],=WH6CN(3)[6],=WH6CUS(3)[6],=WH6CWD(3)[6],=WH6CXB(3)[6],=WH6CXE(3)[6], - =WH6CXN(3)[6],=WH6CYB(3)[6],=WH6CZ(3)[6],=WH6DAY(3)[6],=WH6DJO(3)[6],=WH6DKC(3)[6],=WH6DLQ(3)[6], - =WH6DMP(3)[6],=WH6DQ(3)[6],=WH6DST(3)[6],=WH6EEC(3)[6],=WH6EEG(3)[6],=WH6EGM(3)[6],=WH6EHW(3)[6], - =WH6EJV(3)[6],=WH6EQB(3)[6],=WH6ESS(3)[6],=WH6ETO(3)[6],=WH6EWE(3)[6],=WH6FCT(3)[6],=WH6FEU(3)[6], - =WH6FL(3)[6],=WH6FOJ(3)[6],=WH6OL(3)[6],=WH6OY(3)[6],=WH6QV(3)[6],=WH6SD(3)[6],=WH6SR(3)[6], - =WH6TI(3)[6],=WH6U(3)[6],=WH6XV(3)[6],=WH6YT(3)[6],=WH6ZV(3)[6],=WH7A(3)[6],=WH7CY(3)[6], - =WH7DB(3)[6],=WH7DE(3)[6],=WH7G(3)[6],=WH7GC(3)[6],=WH7GY(3)[6],=WH7HU(3)[6],=WH7LB(3)[6], - =WH7NS(3)[6],=WH7P(3)[6],=WH7RG(3)[6],=WH7TC(3)[6],=WH7UP(3)[6],=WH7WP(3)[6],=WH7WT(3)[6], - =WH7XP(3)[6],=WL7AAW(3)[6],=WL7AL(3)[6],=WL7AP(3)[6],=WL7AZG(3)[6],=WL7AZL(3)[6],=WL7BHR(3)[6], - =WL7BLM(3)[6],=WL7BM(3)[6],=WL7BNQ(3)[6],=WL7BON(3)[6],=WL7BOO(3)[6],=WL7BSW(3)[6],=WL7BVN(3)[6], - =WL7CAZ(3)[6],=WL7CBF(3)[6],=WL7CES(3)[6],=WL7COQ(3)[6],=WL7CPE(3)[6],=WL7CPI(3)[6],=WL7CQX(3)[6], - =WL7CRJ(3)[6],=WL7CSL(3)[6],=WL7CTB(3)[6],=WL7CTC(3)[6],=WL7CTE(3)[6],=WL7DD(3)[6],=WL7FA(3)[6], - =WL7FU(3)[6],=WL7H(3)[6],=WL7HE(3)[6],=WL7HK(3)[6],=WL7HL(3)[6],=WL7IQ(3)[6],=WL7IS(3)[6], - =WL7JM(3)[6],=WL7K(3)[6],=WL7K/7(3)[6],=WL7K/M(3)[6],=WL7LB(3)[6],=WL7LK(3)[6],=WL7OA(3)[6], - =WL7P(3)[6],=WL7PJ(3)[6],=WL7QC(3)[6],=WL7QX(3)[6],=WL7RV/140(3)[6],=WL7SD(3)[6],=WL7SO(3)[6], - =WL7SV(3)[6],=WL7T(3)[6],=WL7VK(3)[6],=WL7WB(3)[6],=WL7WF(3)[6],=WL7WG(3)[6],=WL7WU(3)[6], - =WL7XE(3)[6],=WL7XJ(3)[6],=WL7XN(3)[6],=WL7XW(3)[6],=WL7Z(3)[6],=WL7ZM(3)[6],=WP4BZG(3)[6], - =WP4DYP(3)[6],=WP4NBP(3)[6], + =KL2K(3)[6],=KL2KY(3)[6],=KL2LA(3)[6],=KL2LN(3)[6],=KL2LT(3)[6],=KL2MA(3)[6],=KL2MP(3)[6], + =KL2NJ(3)[6],=KL2NU(3)[6],=KL2NW(3)[6],=KL2OH(3)[6],=KL2OJ(3)[6],=KL2P(3)[6],=KL2QE(3)[6], + =KL2VK(3)[6],=KL2YH(3)[6],=KL3EZ(3)[6],=KL3FE(3)[6],=KL3IC(3)[6],=KL3IO(3)[6],=KL3IW(3)[6], + =KL3MZ(3)[6],=KL3NE(3)[6],=KL3NO(3)[6],=KL3OQ(3)[6],=KL3PD(3)[6],=KL3TW(3)[6],=KL3TY(3)[6], + =KL3VJ(3)[6],=KL3XS(3)[6],=KL4BQ(3)[6],=KL4BS(3)[6],=KL4E(3)[6],=KL4RKH(3)[6],=KL4YFD(3)[6], + =KL7AB(3)[6],=KL7AD(3)[6],=KL7AW(3)[6],=KL7BD(3)[6],=KL7BDC(3)[6],=KL7BH(3)[6],=KL7BR(3)[6], + =KL7BS(3)[6],=KL7BT(3)[6],=KL7BUR(3)[6],=KL7BXP(3)[6],=KL7C(3)[6],=KL7CPO(3)[6],=KL7CT(3)[6], + =KL7CY(3)[6],=KL7DC(3)[6],=KL7DF(3)[6],=KL7DI(3)[6],=KL7DK(3)[6],=KL7DLG(3)[6],=KL7EF(3)[6], + =KL7EFL(3)[6],=KL7EH(3)[6],=KL7EIN(3)[6],=KL7EU(3)[6],=KL7FDQ(3)[6],=KL7FDQ/7(3)[6],=KL7FOZ(3)[6], + =KL7FRQ(3)[6],=KL7FS(3)[6],=KL7GA(3)[6],=KL7GCS(3)[6],=KL7GKY(3)[6],=KL7GRF(3)[6],=KL7GT(3)[6], + =KL7HB(3)[6],=KL7HBV(3)[6],=KL7HFI/7(3)[6],=KL7HFV(3)[6],=KL7HI(3)[6],=KL7HJR(3)[6],=KL7HLF(3)[6], + =KL7HM(3)[6],=KL7HMK(3)[6],=KL7HQL(3)[6],=KL7HSR(3)[6],=KL7IAL(3)[6],=KL7IBT(3)[6],=KL7IDY(3)[6], + =KL7IEI(3)[6],=KL7IFK(3)[6],=KL7IGB(3)[6],=KL7IHK(3)[6],=KL7IIK(3)[6],=KL7IKV(3)[6],=KL7IL(3)[6], + =KL7IME(3)[6],=KL7IOW(3)[6],=KL7IPV(3)[6],=KL7ISE(3)[6],=KL7IUX(3)[6],=KL7IWC/7(3)[6], + =KL7IZC(3)[6],=KL7IZH(3)[6],=KL7JBB(3)[6],=KL7JDQ(3)[6],=KL7JES(3)[6],=KL7JIJ(3)[6],=KL7JJE(3)[6], + =KL7JKV(3)[6],=KL7KA(3)[6],=KL7KG/7(3)[6],=KL7LG(3)[6],=KL7LI(3)[6],=KL7LX(3)[6],=KL7LZ(3)[6], + =KL7M(3)[6],=KL7MY(3)[6],=KL7MZ(3)[6],=KL7NA(3)[6],=KL7NP(3)[6],=KL7NP/7(3)[6],=KL7OA(3)[6], + =KL7OF(3)[6],=KL7OL(3)[6],=KL7OR(3)[6],=KL7OR/7(3)[6],=KL7OS(3)[6],=KL7OY(3)[6],=KL7PO(3)[6], + =KL7QA(3)[6],=KL7QK(3)[6],=KL7QK/140(3)[6],=KL7QK/7(3)[6],=KL7QR(3)[6],=KL7QR/7(3)[6],=KL7R(3)[6], + =KL7RC(3)[6],=KL7RK(3)[6],=KL7RM(3)[6],=KL7RS(3)[6],=KL7S(3)[6],=KL7SK(3)[6],=KL7SP(3)[6], + =KL7T(3)[6],=KL7TU(3)[6],=KL7UP(3)[6],=KL7UT(3)[6],=KL7VK(3)[6],=KL7VL(3)[6],=KL7VN(3)[6], + =KL7VQ(3)[6],=KL7W(3)[6],=KL7WC(3)[6],=KL7WM(3)[6],=KL7WN(3)[6],=KL7WP(3)[6],=KL7WP/7(3)[6], + =KL7WT(3)[6],=KL7YJ(3)[6],=KL7YQ(3)[6],=KL7YY/M(3)[6],=KL7ZH(3)[6],=KL7ZW(3)[6],=KL8RV(3)[6], + =KL8SU(3)[6],=KL9PC(3)[6],=KP2BX(3)[6],=KP2CB(3)[6],=KP2CT(3)[6],=KP2X(3)[6],=KP2Y(3)[6], + =KP4EFZ(3)[6],=KP4ND(3)[6],=KP4UZ(3)[6],=KP4X(3)[6],=NH0F(3)[6],=NH0K(3)[6],=NH0O(3)[6], + =NH2DM(3)[6],=NH2JE(3)[6],=NH2KR(3)[6],=NH6B(3)[6],=NH6BF(3)[6],=NH6CI(3)[6],=NH6DQ(3)[6], + =NH6DX(3)[6],=NH6FF(3)[6],=NH6GZ(3)[6],=NH6HE(3)[6],=NH6HZ(3)[6],=NH6LF(3)[6],=NH6LM(3)[6], + =NH6NS(3)[6],=NH6U(3)[6],=NH6XN(3)[6],=NH6XP(3)[6],=NH6Z(3)[6],=NH6ZA(3)[6],=NH6ZE(3)[6], + =NH7FZ(3)[6],=NH7L(3)[6],=NH7M(3)[6],=NH7MY(3)[6],=NH7N(3)[6],=NH7ND(3)[6],=NH7NJ/7(3)[6], + =NH7OC(3)[6],=NH7PL(3)[6],=NH7RS(3)[6],=NH7S(3)[6],=NH7SH(3)[6],=NH7TG(3)[6],=NH7VZ(3)[6], + =NH7W(3)[6],=NH7WT(3)[6],=NH7WU(3)[6],=NH7YE(3)[6],=NH7YI(3)[6],=NL7AH(3)[6],=NL7AR(3)[6], + =NL7AZ(3)[6],=NL7CH(3)[6],=NL7D(3)[6],=NL7D/7(3)[6],=NL7DH(3)[6],=NL7DY(3)[6],=NL7EO(3)[6], + =NL7FQ(3)[6],=NL7FX(3)[6],=NL7GM(3)[6],=NL7GO(3)[6],=NL7GW(3)[6],=NL7HH(3)[6],=NL7HK(3)[6], + =NL7HQ(3)[6],=NL7HU(3)[6],=NL7IN(3)[6],=NL7JJ(3)[6],=NL7JN(3)[6],=NL7KV(3)[6],=NL7LI(3)[6], + =NL7MS(3)[6],=NL7MT(3)[6],=NL7NL(3)[6],=NL7OF(3)[6],=NL7PN(3)[6],=NL7QI(3)[6],=NL7RL(3)[6], + =NL7TK(3)[6],=NL7UE(3)[6],=NL7US(3)[6],=NL7WD(3)[6],=NL7WJ(3)[6],=NL7XX(3)[6],=NL7ZM(3)[6], + =NL7ZN(3)[6],=NL7ZP(3)[6],=NP2CT(3)[6],=NP2KL(3)[6],=NP2X/7(3)[6],=NP3PH(3)[6],=NP4AI/M(3)[6], + =NP4ES(3)[6],=NP4FP(3)[6],=NP4I(3)[6],=NP4JV(3)[6],=NP4JV/7(3)[6],=VA2GLB/P(3)[6],=WH0AAM(3)[6], + =WH0J(3)[6],=WH2ACV(3)[6],=WH2AJF(3)[6],=WH6ARU(3)[6],=WH6ASB(3)[6],=WH6B(3)[6],=WH6BDR(3)[6], + =WH6BLM(3)[6],=WH6BPU(3)[6],=WH6CF(3)[6],=WH6CMS(3)[6],=WH6CN(3)[6],=WH6CUS(3)[6],=WH6CWD(3)[6], + =WH6CXB(3)[6],=WH6CXE(3)[6],=WH6CXN(3)[6],=WH6CYB(3)[6],=WH6CZ(3)[6],=WH6DAY(3)[6],=WH6DJO(3)[6], + =WH6DKC(3)[6],=WH6DLQ(3)[6],=WH6DMP(3)[6],=WH6DQ(3)[6],=WH6DST(3)[6],=WH6EEC(3)[6],=WH6EEG(3)[6], + =WH6EGM(3)[6],=WH6EHW(3)[6],=WH6EJV(3)[6],=WH6EQB(3)[6],=WH6ESS(3)[6],=WH6ETO(3)[6],=WH6EWE(3)[6], + =WH6FCT(3)[6],=WH6FEU(3)[6],=WH6FL(3)[6],=WH6FOJ(3)[6],=WH6OL(3)[6],=WH6OY(3)[6],=WH6QV(3)[6], + =WH6SD(3)[6],=WH6SR(3)[6],=WH6TI(3)[6],=WH6U(3)[6],=WH6XV(3)[6],=WH6YT(3)[6],=WH6ZR(3)[6], + =WH6ZV(3)[6],=WH7A(3)[6],=WH7CY(3)[6],=WH7DB(3)[6],=WH7DE(3)[6],=WH7G(3)[6],=WH7GC(3)[6], + =WH7GY(3)[6],=WH7HU(3)[6],=WH7LB(3)[6],=WH7NS(3)[6],=WH7P(3)[6],=WH7RG(3)[6],=WH7TC(3)[6], + =WH7U(3)[6],=WH7UP(3)[6],=WH7WP(3)[6],=WH7WT(3)[6],=WH7XP(3)[6],=WL7AAW(3)[6],=WL7AL(3)[6], + =WL7AP(3)[6],=WL7AUY(3)[6],=WL7AZG(3)[6],=WL7AZL(3)[6],=WL7BCR(3)[6],=WL7BHR(3)[6],=WL7BLM(3)[6], + =WL7BM(3)[6],=WL7BNQ(3)[6],=WL7BON(3)[6],=WL7BOO(3)[6],=WL7BSW(3)[6],=WL7BUI(3)[6],=WL7BVN(3)[6], + =WL7BVS(3)[6],=WL7CAZ(3)[6],=WL7CBF(3)[6],=WL7CES(3)[6],=WL7COQ(3)[6],=WL7CPE(3)[6],=WL7CPI(3)[6], + =WL7CQX(3)[6],=WL7CRJ(3)[6],=WL7CSL(3)[6],=WL7CTB(3)[6],=WL7CTC(3)[6],=WL7CTE(3)[6],=WL7DD(3)[6], + =WL7FA(3)[6],=WL7FR(3)[6],=WL7FU(3)[6],=WL7H(3)[6],=WL7HE(3)[6],=WL7HK(3)[6],=WL7HL(3)[6], + =WL7IQ(3)[6],=WL7IS(3)[6],=WL7JM(3)[6],=WL7K(3)[6],=WL7K/7(3)[6],=WL7K/M(3)[6],=WL7LB(3)[6], + =WL7LK(3)[6],=WL7OA(3)[6],=WL7P(3)[6],=WL7PJ(3)[6],=WL7QC(3)[6],=WL7QX(3)[6],=WL7RV/140(3)[6], + =WL7SD(3)[6],=WL7SO(3)[6],=WL7SV(3)[6],=WL7T(3)[6],=WL7VK(3)[6],=WL7WB(3)[6],=WL7WF(3)[6], + =WL7WG(3)[6],=WL7WU(3)[6],=WL7XE(3)[6],=WL7XJ(3)[6],=WL7XN(3)[6],=WL7XW(3)[6],=WL7Z(3)[6], + =WL7ZM(3)[6],=WP2ADG(3)[6],=WP4BZG(3)[6],=WP4DYP(3)[6],=WP4NBP(3)[6], AA8(4)[8],AB8(4)[8],AC8(4)[8],AD8(4)[8],AE8(4)[8],AF8(4)[8],AG8(4)[8],AI8(4)[8],AJ8(4)[8], AK8(4)[8],K8(4)[8],KA8(4)[8],KB8(4)[8],KC8(4)[8],KD8(4)[8],KE8(4)[8],KF8(4)[8],KG8(4)[8], KI8(4)[8],KJ8(4)[8],KK8(4)[8],KM8(4)[8],KN8(4)[8],KO8(4)[8],KQ8(4)[8],KR8(4)[8],KS8(4)[8], @@ -1525,13 +1552,14 @@ United States: 05: 08: NA: 37.53: 91.67: 5.0: K: =AL7AH(4)[8],=AL7BA/8(4)[8],=AL7GI(4)[8],=AL7GI/8(4)[8],=AL7J/8(4)[8],=AL7OP(4)[8],=KH2AP(4)[8], =KH6BZF/8(4)[8],=KH6DHK(4)[8],=KH6IK(4)[8],=KH6ILT(4)[8],=KH6SM(4)[8],=KH7DK(4)[8],=KH7SP(4)[8], =KL0DN(4)[8],=KL0NR(4)[8],=KL0PD(4)[8],=KL0PE(4)[8],=KL2NI(4)[8],=KL2PS(4)[8],=KL2YU(4)[8], - =KL3HQ(4)[8],=KL5A(4)[8],=KL7DS(4)[8],=KL7FHI(4)[8],=KL7FHK(4)[8],=KL7GF(4)[8],=KL7IKR(4)[8], - =KL7OG(4)[8],=KL7RF(4)[8],=KL7RF/8(4)[8],=KL7SW(4)[8],=KL8X(4)[8],=KL9A/8(4)[8],=KP2RF(4)[8], - =KP4AKB(4)[8],=KP4AMZ(4)[8],=KP4AQI(4)[8],=KP4E(4)[8],=KP4MAS(4)[8],=KP4VZ(4)[8],=KP4ZD(4)[8], - =NH6CN(4)[8],=NH6CN/8(4)[8],=NL7CF(4)[8],=NL7FK(4)[8],=NP2AK(4)[8],=NP2F(4)[8],=NP3NA(4)[8], - =VE3ACW/M(4)[8],=WH2U(4)[8],=WH6CYR(4)[8],=WH6E(4)[8],=WH6E/8(4)[8],=WH6EBA(4)[8],=WH6EJD(4)[8], - =WH6TB(4)[8],=WL7AM(4)[8],=WL7BKR(4)[8],=WL7CMV(4)[8],=WL7OS(4)[8],=WL7OT(4)[8],=WP3KU(4)[8], - =WP3S(4)[8],=WP4HJF(4)[8],=WP4NAE(4)[8],=WP4NYQ(4)[8],=WP4PLR(4)[8], + =KL3HQ(4)[8],=KL4PQ(4)[8],=KL5A(4)[8],=KL7DS(4)[8],=KL7FHI(4)[8],=KL7FHK(4)[8],=KL7GF(4)[8], + =KL7IKR(4)[8],=KL7OG(4)[8],=KL7RF(4)[8],=KL7RF/8(4)[8],=KL7SW(4)[8],=KL8X(4)[8],=KL9A/8(4)[8], + =KP2RF(4)[8],=KP4AKB(4)[8],=KP4AMZ(4)[8],=KP4AQI(4)[8],=KP4E(4)[8],=KP4MAS(4)[8],=KP4VZ(4)[8], + =KP4ZD(4)[8],=NH6CN(4)[8],=NH6CN/8(4)[8],=NL7CF(4)[8],=NL7FK(4)[8],=NP2AK(4)[8],=NP2F(4)[8], + =NP3NA(4)[8],=VE3ACW/M(4)[8],=WH2U(4)[8],=WH6CYR(4)[8],=WH6E(4)[8],=WH6E/8(4)[8],=WH6EBA(4)[8], + =WH6EJD(4)[8],=WH6EWB(4)[8],=WH6TB(4)[8],=WL7AGO(4)[8],=WL7AM(4)[8],=WL7BKR(4)[8],=WL7CMV(4)[8], + =WL7OS(4)[8],=WL7OT(4)[8],=WP3KU(4)[8],=WP3S(4)[8],=WP4HJF(4)[8],=WP4MWB(4)[8],=WP4NAE(4)[8], + =WP4NYQ(4)[8],=WP4PLR(4)[8], AA9(4)[8],AB9(4)[8],AC9(4)[8],AD9(4)[8],AE9(4)[8],AF9(4)[8],AG9(4)[8],AI9(4)[8],AJ9(4)[8], AK9(4)[8],K9(4)[8],KA9(4)[8],KB9(4)[8],KC9(4)[8],KD9(4)[8],KE9(4)[8],KF9(4)[8],KG9(4)[8], KI9(4)[8],KJ9(4)[8],KK9(4)[8],KM9(4)[8],KN9(4)[8],KO9(4)[8],KQ9(4)[8],KR9(4)[8],KS9(4)[8], @@ -1542,54 +1570,58 @@ United States: 05: 08: NA: 37.53: 91.67: 5.0: K: WE9(4)[8],WF9(4)[8],WG9(4)[8],WI9(4)[8],WJ9(4)[8],WK9(4)[8],WM9(4)[8],WN9(4)[8],WO9(4)[8], WQ9(4)[8],WR9(4)[8],WS9(4)[8],WT9(4)[8],WU9(4)[8],WV9(4)[8],WW9(4)[8],WX9(4)[8],WY9(4)[8], WZ9(4)[8],=AH0AJ(4)[8],=AH6DA(4)[8],=AH6EZ/9(4)[8],=AH6OM(4)[8],=AL1CE(4)[8],=AL7AK(4)[8], - =AL7AK/9(4)[8],=AL7BT(4)[8],=AL7CV(4)[8],=AL7DS(4)[8],=AL7II/9(4)[8],=AL7OL(4)[8],=KH0BE(4)[8], - =KH6JNY(4)[8],=KH6KI(4)[8],=KH6UX(4)[8],=KH7DR(4)[8],=KH7EI(4)[8],=KL0LB(4)[8],=KL0NY(4)[8], - =KL1NO(4)[8],=KL1QN(4)[8],=KL2A/9(4)[8],=KL2KP(4)[8],=KL2NQ(4)[8],=KL2YD(4)[8],=KL2ZL(4)[8], - =KL4CX(4)[8],=KL7AL(4)[8],=KL7AL/9(4)[8],=KL7BGR(4)[8],=KL7CE(4)[8],=KL7CE/9(4)[8],=KL7IBV(4)[8], - =KL7IPS(4)[8],=KL7IVK(4)[8],=KL7JAB(4)[8],=KL7MU(4)[8],=KP3JOS(4)[8],=KP3VA/M(4)[8],=KP4CI(4)[8], - =KP4GE(4)[8],=KP4SL(4)[8],=KP4WG(4)[8],=NH2W(4)[8],=NH2W/9(4)[8],=NH6R(4)[8],=NH7TK(4)[8], - =NL7CM(4)[8],=NL7KD(4)[8],=NL7NK(4)[8],=NL7QC(4)[8],=NL7QC/9(4)[8],=NL7RC(4)[8],=NL7UH(4)[8], - =NL7YI(4)[8],=NP2AV(4)[8],=NP2GM(4)[8],=NP2L/9(4)[8],=NP2MU(4)[8],=NP3QC(4)[8],=NP4JS(4)[8], - =NP4ZI(4)[8],=WH0AI(4)[8],=WH2T(4)[8],=WH6FBA(4)[8],=WH6SB(4)[8],=WL7AHP(4)[8],=WL7AIT(4)[8], - =WL7CTA(4)[8],=WL7FJ(4)[8],=WL7JAN(4)[8],=WL7NP(4)[8],=WL7UU(4)[8],=WP2B(4)[8],=WP4JSP(4)[8], - =WP4KGF(4)[8],=WP4LKY(4)[8],=WP4LSQ(4)[8],=WP4MQX(4)[8],=WP4MSD(4)[8],=WP4MTN(4)[8],=WP4MVQ(4)[8], - =WP4MYL(4)[8],=WP4OCZ(4)[8], + =AL7AK/9(4)[8],=AL7BT(4)[8],=AL7CV(4)[8],=AL7DS(4)[8],=AL7II/9(4)[8],=AL7OL(4)[8],=AL7PM(4)[8], + =KH0BE(4)[8],=KH2RP(4)[8],=KH6JNY(4)[8],=KH6KI(4)[8],=KH6UX(4)[8],=KH7DR(4)[8],=KH7EI(4)[8], + =KL0LB(4)[8],=KL0NY(4)[8],=KL1NO(4)[8],=KL1QN(4)[8],=KL2A/9(4)[8],=KL2KP(4)[8],=KL2NQ(4)[8], + =KL2YD(4)[8],=KL2ZL(4)[8],=KL4CX(4)[8],=KL7AL(4)[8],=KL7AL/9(4)[8],=KL7BGR(4)[8],=KL7CE(4)[8], + =KL7CE/9(4)[8],=KL7IBV(4)[8],=KL7IPS(4)[8],=KL7IVK(4)[8],=KL7JAB(4)[8],=KL7MU(4)[8],=KL7TD(4)[8], + =KP2XX(4)[8],=KP3JOS(4)[8],=KP3VA/M(4)[8],=KP4CI(4)[8],=KP4GE/9(4)[8],=KP4SL(4)[8],=KP4WG(4)[8], + =NH2W(4)[8],=NH2W/9(4)[8],=NH6R(4)[8],=NH7TK(4)[8],=NL7CM(4)[8],=NL7KD(4)[8],=NL7NK(4)[8], + =NL7QC(4)[8],=NL7QC/9(4)[8],=NL7RC(4)[8],=NL7UH(4)[8],=NL7YI(4)[8],=NP2AV(4)[8],=NP2GM(4)[8], + =NP2L/9(4)[8],=NP2MU(4)[8],=NP3QC(4)[8],=NP4ZI(4)[8],=WH0AI(4)[8],=WH2T(4)[8],=WH6ERQ(4)[8], + =WH6FBA(4)[8],=WH6SB(4)[8],=WL7AHP(4)[8],=WL7AIT(4)[8],=WL7BEV(4)[8],=WL7CTA(4)[8],=WL7FJ(4)[8], + =WL7JAN(4)[8],=WL7NP(4)[8],=WL7UU(4)[8],=WP2B(4)[8],=WP4JSP(4)[8],=WP4KGF(4)[8],=WP4LKY(4)[8], + =WP4LSQ(4)[8],=WP4MQX(4)[8],=WP4MSD(4)[8],=WP4MTN(4)[8],=WP4MVQ(4)[8],=WP4MYL(4)[8],=WP4OCZ(4)[8], =AH2BG(4)[8],=AH6ES(4)[8],=AH6FF(4)[8],=AH6HR(4)[8],=AH6HR/4(4)[8],=AH6KB(4)[8],=AL0P(4)[8], =AL2C(4)[8],=AL2F(4)[8],=AL2F/4(4)[8],=AL4B(4)[8],=AL7CX(4)[8],=AL7EU(4)[8],=AL7KN(4)[8], =AL7MR(4)[8],=AL7QO(4)[8],=KH0UN(4)[8],=KH2AR(4)[8],=KH2AR/4(4)[8],=KH2DN(4)[8],=KH4AF(4)[8], - =KH6EO(4)[8],=KH6JQW(4)[8],=KH6OE(4)[8],=KH6RD(4)[8],=KH6RD/4(4)[8],=KH6SKY(4)[8],=KH6SKY/4(4)[8], - =KH7JM(4)[8],=KH7UB(4)[8],=KL0AH(4)[8],=KL0BX(4)[8],=KL0CP(4)[8],=KL0ET(4)[8],=KL0ET/M(4)[8], - =KL0EY(4)[8],=KL0FF(4)[8],=KL0GI(4)[8],=KL0LN(4)[8],=KL0PM(4)[8],=KL0VH(4)[8],=KL1DN(4)[8], - =KL1IG(4)[8],=KL1LV(4)[8],=KL1SE(4)[8],=KL1SE/4(4)[8],=KL1ZA(4)[8],=KL2GB(4)[8],=KL2HK(4)[8], - =KL2LK(4)[8],=KL2LU(4)[8],=KL2MU(4)[8],=KL2UC(4)[8],=KL3AA(4)[8],=KL3PG(4)[8],=KL4KA(4)[8], - =KL7DT/4(4)[8],=KL7FO/P(4)[8],=KL7GN/M(4)[8],=KL7IUQ(4)[8],=KL7JKC(4)[8],=KL7LT(4)[8], - =KL7WW(4)[8],=KL7YN(4)[8],=KL7YT(4)[8],=KL9MEK(4)[8],=KP3RC(4)[8],=KP4TOM(4)[8],=NH2E(4)[8], - =NH6T/4(4)[8],=NH7FK(4)[8],=NH7FL(4)[8],=NH7H(4)[8],=NL7OE(4)[8],=NL7YU(4)[8],=NP4AC(4)[8], - =NP4AC/4(4)[8],=WH6AUL(4)[8],=WH6BPL(4)[8],=WH6BPL/4(4)[8],=WH6DM(4)[8],=WH6EOG(4)[8], - =WH6FEJ(4)[8],=WH6LAK(4)[8],=WL4B(4)[8],=WL7BHI(4)[8],=WL7BHJ(4)[8],=WL7CQH(4)[8],=WL7CQK(4)[8], - =WL7IP(4)[8],=WL7PC(4)[8],=WL7SF(4)[8],=WL7TD(4)[8],=WL7XZ(4)[8],=WP4CNA(4)[8], + =KH6EO(4)[8],=KH6JQW(4)[8],=KH6KM(4)[8],=KH6OE(4)[8],=KH6RD(4)[8],=KH6RD/4(4)[8],=KH6SKY(4)[8], + =KH6SKY/4(4)[8],=KH7JM(4)[8],=KH7UB(4)[8],=KL0AH(4)[8],=KL0BX(4)[8],=KL0CP(4)[8],=KL0ET(4)[8], + =KL0ET/M(4)[8],=KL0EY(4)[8],=KL0FF(4)[8],=KL0GI(4)[8],=KL0LN(4)[8],=KL0PM(4)[8],=KL0VH(4)[8], + =KL1DN(4)[8],=KL1IG(4)[8],=KL1LV(4)[8],=KL1SE(4)[8],=KL1SE/4(4)[8],=KL1ZA(4)[8],=KL2GB(4)[8], + =KL2HK(4)[8],=KL2LK(4)[8],=KL2LU(4)[8],=KL2MU(4)[8],=KL2UC(4)[8],=KL3PG(4)[8],=KL3PV(4)[8], + =KL4KA(4)[8],=KL7DT/4(4)[8],=KL7FO/P(4)[8],=KL7GN/M(4)[8],=KL7IUQ(4)[8],=KL7JKC(4)[8], + =KL7LT(4)[8],=KL7WW(4)[8],=KL7YN(4)[8],=KL7YT(4)[8],=KL9MEK(4)[8],=KP3RC(4)[8],=KP4TOM(4)[8], + =NH2E(4)[8],=NH6T/4(4)[8],=NH7FK(4)[8],=NH7FL(4)[8],=NH7H(4)[8],=NL7OE(4)[8],=NL7YU(4)[8], + =NP3FB(4)[8],=NP4AC(4)[8],=NP4AC/4(4)[8],=WH6AUL(4)[8],=WH6BPL(4)[8],=WH6BPL/4(4)[8],=WH6DM(4)[8], + =WH6EOG(4)[8],=WH6EQW(4)[8],=WH6FEJ(4)[8],=WH6LAK(4)[8],=WH6Q/4(4)[8],=WL4B(4)[8],=WL7BHI(4)[8], + =WL7BHJ(4)[8],=WL7CQH(4)[8],=WL7CQK(4)[8],=WL7IP(4)[8],=WL7PC(4)[8],=WL7SF(4)[8],=WL7TD(4)[8], + =WL7XZ(4)[8],=WP4CNA(4)[8], =AL7AU(4)[7],=AL7NI(4)[7],=AL7RT(4)[7],=AL7RT/7(4)[7],=KH2BR/7(4)[7],=KH6JVF(4)[7],=KH6OZ(4)[7], - =KH7SS(4)[7],=KL0NT(4)[7],=KL0NV(4)[7],=KL0RN(4)[7],=KL1HE(4)[7],=KL1MW(4)[7],=KL1TV(4)[7], - =KL2NZ(4)[7],=KL7AR(4)[7],=KL7HF(4)[7],=KL7JGS(4)[7],=KL7JGS/M(4)[7],=KL7JM(4)[7],=KL7LH(4)[7], - =KL7MVX(4)[7],=KL7YY/7(4)[7],=KL9A(4)[7],=KL9A/7(4)[7],=NH0E(4)[7],=NH6HW(4)[7],=WH2M(4)[7], - =WH6COM(4)[7],=WH6ETU(4)[7],=WH6EVP(4)[7],=WL7A(4)[7],=WL7DP(4)[7],=WL7HP/7(4)[7],=WL7I(4)[7], + =KH7SS(4)[7],=KL0NT(4)[7],=KL0NV(4)[7],=KL0RN(4)[7],=KL0TF(4)[7],=KL1HE(4)[7],=KL1MW(4)[7], + =KL1TV(4)[7],=KL2NZ(4)[7],=KL4CZ(4)[7],=KL7AR(4)[7],=KL7HF(4)[7],=KL7JGS(4)[7],=KL7JGS/M(4)[7], + =KL7JM(4)[7],=KL7JUL(4)[7],=KL7LH(4)[7],=KL7MVX(4)[7],=KL7YY/7(4)[7],=KL9A(4)[7],=KL9A/7(4)[7], + =NH0E(4)[7],=NH6HW(4)[7],=NL7IH(4)[7],=NL7MW(4)[7],=NL7UI(4)[7],=WH2M(4)[7],=WH6COM(4)[7], + =WH6ETU(4)[7],=WH6EVP(4)[7],=WL7A(4)[7],=WL7DP(4)[7],=WL7HP/7(4)[7],=WL7I(4)[7], =AL7LU(5)[8],=KL7JFR(5)[8],=WL7HC(5)[8],=WP4GR(5)[8]; Guantanamo Bay: 08: 11: NA: 20.00: 75.00: 5.0: KG4: KG4,=KG44WW,=KG4AC,=KG4AS,=KG4AW,=KG4AY,=KG4BP,=KG4DY,=KG4EM,=KG4EU,=KG4HF,=KG4HH,=KG4LA,=KG4LB, =KG4SC,=KG4SS,=KG4WH,=KG4WV,=KG4XP,=KG4ZK,=W1AW/KG4; Mariana Islands: 27: 64: OC: 15.18: -145.72: -10.0: KH0: - AH0,KH0,NH0,WH0,=AB2QH,=AB9HF,=AB9OQ,=AD5KT,=AD6YP,=AE6OG,=AF4IN,=AF4KH,=AF6EO,=AH2U,=AJ6K,=AK1JA, - =KB5UAB,=KB9LQG,=KC5SPG,=KC7SDC,=KC9GQX,=KD7GJX,=KG6GQ,=KG6SB,=KG7DCN,=KH0EN/KT,=KH2GV,=KH2O, - =KH2VL,=KL7QOL,=KW2X,=N0J,=N2AIR,=N3QD,=N6EAX,=N7NVX,=N8CS,=NA1M,=NH2B,=NH2FG,=NU2A,=W1FPU,=W3FM, - =W3NL,=W3STX,=W7KFS,=WA6AC,=WE1J,=WH6ZW,=WO2G; + AH0,KH0,NH0,WH0,=AB2HV,=AB2QH,=AB9HF,=AB9OQ,=AC8CP,=AD5KT,=AD6YP,=AE6OG,=AF4IN,=AF4KH,=AF6EO, + =AH2U,=AJ6K,=AK1JA,=K0FRI,=K8KH,=K8RN,=KB5UAB,=KB9LQG,=KC2WIK,=KC5SPG,=KC7SDC,=KC9GQX,=KD7GJX, + =KF7COQ,=KG2QH,=KG6GQ,=KG6SB,=KG7DCN,=KH0EN/KT,=KH2GV,=KH2O,=KH2VL,=KL7QOL,=KW2X,=N0J,=N3QD, + =N6EAX,=N7NVX,=N8CS,=NA1M,=NH2B,=NH2FG,=NO3V,=NS0C,=NU2A,=W1FPU,=W3FM,=W3NL,=W3STX,=W7KFS,=WA6AC, + =WE1J,=WH6ZW,=WO2G; Baker & Howland Islands: 31: 61: OC: 0.00: 176.00: 12.0: KH1: AH1,KH1,NH1,WH1; Guam: 27: 64: OC: 13.37: -144.70: -10.0: KH2: - AH2,KH2,NH2,WH2,=AB2AB,=AC0FG,=AE6QZ,=AH0AX,=AH0F,=AH0S,=AI6ID,=K1IWD,=K2QGC,=K5GUA,=K5GUM,=KA0RU, - =KA6BEG,=KB7OVT,=KB7PQU,=KC2OOX,=KD7IRV,=KE4YSP,=KE6ATM,=KE7GMC,=KE7IPG,=KF4UFC,=KF5ULC,=KF7BMU, - =KG4BKW,=KG6AGT,=KG6ARL,=KG6DX,=KG6FJG,=KG6JDX,=KG6JKR,=KG6JKT,=KG6TEZ,=KG6TWZ,=KH0C,=KH0DX, - =KH0ES,=KH0TF,=KH6KK,=KI4KKH,=KI4KKI,=KI7SSW,=KJ6KCJ,=KK6GVF,=KK7AV,=KM4NVB,=N2MI,=NH0A,=NH0B, - =NH7TL,=NH7WC,=NP3EZ,=W5LFA,=W6KV,=W7GVC,=W9MRE,=WA3KNB,=WB7AXZ,=WD6DGS,=WH0AC; + AH2,KH2,NH2,WH2,=AB2AB,=AB8EW,=AC0FG,=AC7WL,=AE6QZ,=AH0AX,=AH0F,=AH0FM,=AH0S,=AI6ID,=AJ6JF,=K1IWD, + =K2QGC,=K5GUA,=K5GUM,=KA0RU,=KA1I,=KA6BEG,=KB5OXR,=KB7OVT,=KB7PQU,=KC2OOX,=KD7IRV,=KE4YSP,=KE6ATM, + =KE7GMC,=KE7IPG,=KF4UFC,=KF5ULC,=KF7BMU,=KG4BKW,=KG6AGT,=KG6ARL,=KG6DX,=KG6FJG,=KG6JDX,=KG6JKR, + =KG6JKT,=KG6TWZ,=KH0C,=KH0DX,=KH0ES,=KH0TF,=KH0UM,=KH6KK,=KI4KKH,=KI4KKI,=KI7SSW,=KJ6KCJ,=KK6GVF, + =KK7AV,=KM4NVB,=N2MI,=NH0A,=NH0B,=NH0Q,=NH7TL,=NH7WC,=NP3EZ,=W5LFA,=W6KV,=W7GVC,=W9MRE,=WA3KNB, + =WB7AXZ,=WD6DGS,=WH0AC; Johnston Island: 31: 61: OC: 16.72: 169.53: 10.0: KH3: AH3,KH3,NH3,WH3,=KJ6BZ; Midway Island: 31: 61: OC: 28.20: 177.37: 11.0: KH4: @@ -1599,47 +1631,49 @@ Palmyra & Jarvis Islands: 31: 61: OC: 5.87: 162.07: 11.0: KH5: Hawaii: 31: 61: OC: 21.12: 157.48: 10.0: KH6: AH6,AH7,KH6,KH7,NH6,NH7,WH6,WH7,=AA7LE,=AA8JA,=AB0JM,=AB3WS,=AB6AP,=AB8VQ,=AC4PJ,=AC4TJ,=AC7LR, =AC7N,=AC9PT,=AE3TT,=AE5AB,=AE5LR,=AG4FH,=AH0A,=AH0AG,=AH2CN,=AJ0M,=AJ8HT,=AK0P,=AK2J,=AL3U, - =AL7RQ,=K0BAD,=K0LAS,=K0LIH,=K0LUC,=K0OUS,=K1ENT,=K1HZM,=K1OWL,=K1RJ,=K1VAN,=K2FFT,=K2GT,=K3NW, - =K3QHP,=K3UNS,=K4EVR,=K4RAC,=K4UAI,=K4UHL,=K4XS,=K4XSS,=K4XV,=K5HQM,=K5ZAI,=K5ZYO,=K6AMA,=K6APP, - =K6ATF,=K6CEE,=K6DCH,=K6GJS,=K6GUY,=K6HI,=K6JAE,=K6MIO,=K6NLF,=K6RSB,=K7ASH,=K7FAR,=K7FR,=K7NRJ, - =K7QAS,=K8EUT,=K9AGI,=K9FD,=K9UBS,=KA0FOR,=KA0VHP,=KA1ICJ,=KA1YJ,=KA2IXG,=KA2WXU,=KA3HIZ,=KA3TUA, - =KA4INK,=KA6QOD,=KA7APU,=KA7RKW,=KA8EBL,=KA8KND,=KA9DMP,=KB0DJR,=KB0PXK,=KB0ZKZ,=KB1EUJ,=KB1GC, - =KB1PCX,=KB2MRY,=KB3DMT,=KB3IOC,=KB3OXU,=KB3PJS,=KB3SEV,=KB4NGN,=KB5NNY,=KB5OWT,=KB6CNU,=KB6EGA, - =KB6PKF,=KB7AKH,=KB7DDX,=KB7EA,=KB7G,=KB7JB,=KB7MEU,=KB7QKJ,=KB7UQH,=KB7UVR,=KB7WUP,=KB8SKX, - =KC0WQU,=KC0YIH,=KC0ZER,=KC1DBY,=KC2GSU,=KC2HL,=KC2MIU,=KC2PGW,=KC2SRW,=KC2YL,=KC2ZSG,=KC2ZSH, - =KC2ZSI,=KC3GZT,=KC4HHS,=KC5GAX,=KC6HOX,=KC6QQI,=KC6RYQ,=KC6SHT,=KC6SWR,=KC6YIO,=KC7ASJ,=KC7AXX, - =KC7DUT,=KC7EJC,=KC7HNC,=KC7KAT,=KC7KAW,=KC7KBA,=KC7KHW,=KC7KJT,=KC7LFM,=KC7NZ,=KC7PLG,=KC7USA, - =KC7VHF,=KC7VWU,=KC7YXO,=KC8EFI,=KC8EJ,=KC9AUA,=KC9EQS,=KC9KEX,=KC9NJG,=KC9SBG,=KD0QLQ,=KD0QLR, - =KD0RPD,=KD0WVZ,=KD0ZSP,=KD3FZ,=KD4GW,=KD4ML,=KD4QWO,=KD5ACN,=KD5BSK,=KD5HDA,=KD5HX,=KD5TBQ, - =KD6CVU,=KD6CWF,=KD6EPD,=KD6IPX,=KD6LRA,=KD6VTU,=KD7HTG,=KD7LMP,=KD7SME,=KD7SMV,=KD7TZ,=KD7UV, - =KD7UZG,=KD7WJM,=KD8GVO,=KE0TU,=KE2CX,=KE4DYE,=KE4RNU,=KE4UXQ,=KE4ZXQ,=KE5CGA,=KE5FJM,=KE5UZN, - =KE6AXN,=KE6AXP,=KE6AYZ,=KE6CQE,=KE6EDJ,=KE6EVT,=KE6JXO,=KE6RAW,=KE6TFR,=KE6TIS,=KE6TKQ,=KE7FJA, - =KE7FSK,=KE7HEW,=KE7IZS,=KE7JTX,=KE7KRQ,=KE7LWN,=KE7MW,=KE7PEQ,=KE7PIZ,=KE7RCT,=KE7UAJ,=KE7UV, + =AL7RQ,=K0BAD,=K0LAS,=K0LIH,=K0LUC,=K0OUS,=K1ENT,=K1HZM,=K1OSP,=K1OWL,=K1RJ,=K1VAN,=K2FFT,=K2GT, + =K3NW,=K3QHP,=K3UNS,=K4EVR,=K4RAC,=K4UAI,=K4UHL,=K4XS,=K4XSS,=K4XV,=K5HQM,=K5UN,=K5ZAI,=K5ZYO, + =K6AMA,=K6APP,=K6ATF,=K6BU,=K6CEE,=K6GJS,=K6GUY,=K6HI,=K6JAE,=K6MIO,=K6NLF,=K6RSB,=K7ALH,=K7ASH, + =K7FAR,=K7FR,=K7NRJ,=K7QAS,=K8EUT,=K9AGI,=K9FD,=K9UBS,=KA0FOR,=KA0VHP,=KA1ICJ,=KA1YJ,=KA2IXG, + =KA2WXU,=KA3HIZ,=KA3TUA,=KA4INK,=KA6QOD,=KA7APU,=KA7BSK,=KA7RKW,=KA8EBL,=KA8KND,=KA9DMP,=KB0DJR, + =KB0PXK,=KB0ZKZ,=KB1EUJ,=KB1GC,=KB1PCX,=KB1UHL,=KB2MRY,=KB3DMT,=KB3IOC,=KB3OXU,=KB3PJS,=KB3SEV, + =KB4NGN,=KB5HVJ,=KB5NNY,=KB5OWT,=KB6CNU,=KB6EGA,=KB6INB,=KB6PKF,=KB7AKH,=KB7DDX,=KB7EA,=KB7G, + =KB7JB,=KB7MEU,=KB7QKJ,=KB7UQH,=KB7UVR,=KB7WDC,=KB7WUP,=KB8SKX,=KC0WQU,=KC0YIH,=KC0ZER,=KC1DBY, + =KC2GSU,=KC2HL,=KC2MIU,=KC2PGW,=KC2SRW,=KC2YL,=KC2ZSG,=KC2ZSH,=KC2ZSI,=KC3GZT,=KC4HHS,=KC5GAX, + =KC6HOX,=KC6QQI,=KC6RYQ,=KC6SHT,=KC6SWR,=KC6YIO,=KC7ASJ,=KC7AXX,=KC7DUT,=KC7EJC,=KC7HNC,=KC7KAT, + =KC7KAW,=KC7KBA,=KC7KHW,=KC7KJT,=KC7LFM,=KC7NZ,=KC7PLG,=KC7USA,=KC7VHF,=KC7VWU,=KC7YXO,=KC8EFI, + =KC8EJ,=KC9AUA,=KC9EQS,=KC9KEX,=KC9NJG,=KC9SBG,=KD0QLQ,=KD0QLR,=KD0RPD,=KD0WVZ,=KD0ZSP,=KD3FZ, + =KD4GW,=KD4ML,=KD4QWO,=KD5ACN,=KD5BSK,=KD5HDA,=KD5HX,=KD5TBQ,=KD6CVU,=KD6CWF,=KD6EPD,=KD6IPX, + =KD6LRA,=KD6NVX,=KD6VTU,=KD7GWM,=KD7HTG,=KD7KFT,=KD7LMP,=KD7SME,=KD7SMV,=KD7TZ,=KD7UV,=KD7UZG, + =KD7WJM,=KD8GVO,=KE0TU,=KE2CX,=KE4DYE,=KE4RNU,=KE4UXQ,=KE4ZXQ,=KE5CGA,=KE5FJM,=KE5UZN,=KE6AXN, + =KE6AXP,=KE6AYZ,=KE6CQE,=KE6EDJ,=KE6EVT,=KE6JXO,=KE6RAW,=KE6TFR,=KE6TIS,=KE6TKQ,=KE7FJA,=KE7FSK, + =KE7HEW,=KE7IZS,=KE7JTX,=KE7KRQ,=KE7LWN,=KE7MW,=KE7PEQ,=KE7PIZ,=KE7QML,=KE7RCT,=KE7UAJ,=KE7UV, =KE7UW,=KF4DWA,=KF4FQR,=KF4IBW,=KF4JLZ,=KF4OOB,=KF4URD,=KF4VHS,=KF5AHW,=KF5LBQ,=KF5MXM,=KF5MXP, =KF6BS,=KF6FDG,=KF6IVV,=KF6LWN,=KF6LYU,=KF6MQT,=KF6OSA,=KF6PJ,=KF6PQE,=KF6QZD,=KF6RLP,=KF6YZR, - =KF6ZAL,=KF7GNP,=KF7IJL,=KF7LRS,=KF7OJR,=KF7TUU,=KF7VUK,=KG0XR,=KG4HZF,=KG4SGC,=KG4SGV,=KG6DV, - =KG6EFD,=KG6HRX,=KG6IGY,=KG6JJP,=KG6LFX,=KG6MZJ,=KG6NNF,=KG6NQI,=KG6OOB,=KG6RJI,=KG6SDD,=KG6TFI, - =KG6WZD,=KG7AYU,=KG7CJI,=KG7CVR,=KG7EUP,=KH0AI,=KH0HL,=KH0WJ,=KH2MD,=KH2TD,=KH2TE,=KH2YI,=KH3AE, - =KH3AE/M,=KH3AF,=KI4CAU,=KI4HCZ,=KI4NOH,=KI4YAF,=KI6CRL,=KI6DVJ,=KI6EFY,=KI6FTE,=KI6HBZ,=KI6JEC, - =KI6LPT,=KI6NOC,=KI6QDQ,=KI6QQJ,=KI6SNP,=KI6VYB,=KI6WOJ,=KI6ZRV,=KI7EZG,=KI7FJW,=KI7FJX,=KI7FUT, - =KI7OS,=KI7QZQ,=KJ4BHO,=KJ4EYV,=KJ4KND,=KJ4WOI,=KJ6GYD,=KJ6LAW,=KJ6LAX,=KJ6LBI,=KJ6NZH,=KJ6QQT, - =KJ6RGW,=KJ6SKC,=KJ6TJZ,=KK4EEC,=KK6BRW,=KK6EJ,=KK6GM,=KK6OMX,=KK6PGA,=KK6QAI,=KK6VJN,=KK6ZQ, - =KK6ZZE,=KK7WR,=KL1TP,=KL3FN,=KL7PN,=KL7UB,=KM6BOQ,=KM6IK,=KM6RM,=KN6BE,=KN6ZU,=KN8AQR,=KO6KW, - =KO6QT,=KQ6CD,=KQ6M,=KU4OY,=KW4JC,=KY1I,=N0CAN,=N0DQD,=N0PJV,=N0RMC,=N0ZSJ,=N1CBF,=N1CFD,=N1CNQ, - =N1IDP,=N1SHV,=N1TEE,=N1TLE,=N1VOP,=N1YLH,=N2AL,=N2KJU,=N2KLQ,=N3DJT,=N3FUR,=N3GWR,=N3HQW,=N3RWD, - =N3VDM,=N3ZFY,=N4ERA,=N4ZIW,=N5IWF,=N5JKJ,=N6AI,=N6CGA,=N6DXW,=N6GOZ,=N6IKX,=N6KB,=N6NCT,=N6PJQ, - =N6QBK,=N6ZAB,=N7AMY,=N7BLC,=N7KZB,=N7NYY,=N7ODC,=N7TSV,=N7WBX,=N9CRQ,=N9GFL,=N9SBL,=NB6R,=NE7SO, - =NG1T,=NH2CC,=NH2CD,=NH2CF,=NH2CQ,=NH2CR,=NH2IB,=NH2IF,=NH2II,=NH2IJ,=NH2IO,=NH2JO,=NH2KF,=NH2KH, - =NH2YL,=NH2Z,=NI1J,=NL7UW,=NM2B,=NO0H,=NT0DA,=NT4AA,=NZ2F,=W0UNX,=W1BMB,=W2UNS,=W3ZRT,=W4YQS, - =W5FJG,=W6AUS,=W6CAG,=W6CWJ,=W6KEV,=W6KIT,=W6KPI,=W6MQB,=W6MRJ,=W6NBK,=W6ROM,=W6SHH,=W6UNX,=W7EHP, - =W7NVQ,=W7NX,=W7OO,=W7RCR,=W7UEA,=W8AYD,=W8JAY,=W8WH,=W9IS,=WA0FUR,=WA0NHD,=WA2AUI,=WA3ZEM, - =WA6ECX,=WA6JDA,=WA6JJQ,=WA6QDQ,=WA6UVF,=WA7ESE,=WA7HEO,=WA7TFE,=WA7ZK,=WA8JQP,=WB0RUA,=WB0TZQ, - =WB2AHM,=WB2SQW,=WB4JTT,=WB4MNF,=WB5ZDH,=WB5ZOV,=WB6CVJ,=WB6PJT,=WB6SAA,=WB8NCD,=WB9SMM,=WC6B, - =WD0FTF,=WD0LFN,=WD6EZL,=WD6GHJ,=WD8LIB,=WD8OBO,=WH2Y,=WH7K,=WJ8A,=WU0H,=WV0Z,=WV6K,=WX7G; + =KF6ZAL,=KF6ZVS,=KF7GNP,=KF7IJL,=KF7LRS,=KF7OJR,=KF7TUU,=KF7VUK,=KG0XR,=KG4HZF,=KG4SGC,=KG4SGV, + =KG6DV,=KG6EFD,=KG6HRX,=KG6IGY,=KG6JJP,=KG6LFX,=KG6MZJ,=KG6NNF,=KG6NQI,=KG6OOB,=KG6RJI,=KG6SDD, + =KG6TFI,=KG6WZD,=KG7AYU,=KG7CJI,=KG7CVR,=KG7EUP,=KH0AI,=KH0HL,=KH0WJ,=KH2MD,=KH2TD,=KH2TE,=KH2YI, + =KH3AE,=KH3AE/M,=KH3AF,=KH8Z,=KI4CAU,=KI4HCZ,=KI4NOH,=KI4YAF,=KI4YOG,=KI6CRL,=KI6DVJ,=KI6EFY, + =KI6FTE,=KI6HBZ,=KI6JEC,=KI6LPT,=KI6NOC,=KI6QDQ,=KI6QQJ,=KI6SNP,=KI6VYB,=KI6WOJ,=KI6ZRV,=KI7EZG, + =KI7FJW,=KI7FJX,=KI7FUT,=KI7OS,=KI7QZQ,=KJ4BHO,=KJ4EYV,=KJ4KND,=KJ4WOI,=KJ6GYD,=KJ6LAW,=KJ6LAX, + =KJ6LBI,=KJ6NZH,=KJ6QQT,=KJ6RGW,=KJ6SKC,=KJ6TJZ,=KK4EEC,=KK6BRW,=KK6EJ,=KK6GM,=KK6OMX,=KK6PGA, + =KK6QAI,=KK6RM,=KK6VJN,=KK6ZQ,=KK6ZZE,=KK7WR,=KL0TK,=KL1TP,=KL3FN,=KL7PN,=KL7UB,=KM6BOQ,=KM6IK, + =KM6RM,=KN6BE,=KN6ZU,=KN8AQR,=KO6KW,=KO6QT,=KQ6CD,=KQ6M,=KU4OY,=KW4JC,=KY1I,=N0CAN,=N0DQD,=N0KXY, + =N0PJV,=N0RMC,=N0ZSJ,=N1CBF,=N1CFD,=N1CNQ,=N1IDP,=N1SHV,=N1TEE,=N1TLE,=N1VOP,=N1YLH,=N2AL,=N2KJU, + =N2KLQ,=N3DJT,=N3FUR,=N3GWR,=N3HQW,=N3RWD,=N3VDM,=N3ZFY,=N4ERA,=N4ZIW,=N5IWF,=N5JKJ,=N6AI,=N6CGA, + =N6DXW,=N6GOZ,=N6IKX,=N6KB,=N6NCT,=N6PJQ,=N6QBK,=N6ZAB,=N7AMY,=N7BLC,=N7KZB,=N7NYY,=N7ODC,=N7TSV, + =N7WBX,=N9CRQ,=N9GFL,=N9SBL,=NB6R,=NE7SO,=NG1T,=NH2CC,=NH2CD,=NH2CF,=NH2CQ,=NH2CR,=NH2IB,=NH2IF, + =NH2II,=NH2IJ,=NH2IO,=NH2JO,=NH2KF,=NH2KH,=NH2YL,=NH2Z,=NI1J,=NL7UW,=NM2B,=NO0H,=NT0DA,=NT4AA, + =NZ2F,=W0UNX,=W1BMB,=W2UNS,=W3ZRT,=W4YQS,=W5FJG,=W6AUS,=W6CAG,=W6CWJ,=W6KEV,=W6KIT,=W6KPI,=W6MQB, + =W6MRJ,=W6NBK,=W6ROM,=W6SHH,=W6UNX,=W7EHP,=W7NVQ,=W7NX,=W7OO,=W7RCR,=W7UEA,=W8AYD,=W8JAY,=W8WH, + =WA0FUR,=WA0NHD,=WA2AUI,=WA3ZEM,=WA6ECX,=WA6IIQ,=WA6JDA,=WA6JJQ,=WA6QDQ,=WA6UVF,=WA7ESE,=WA7HEO, + =WA7TFE,=WA7ZK,=WA8JQP,=WB0RUA,=WB0TZQ,=WB2AHM,=WB2SQW,=WB4JTT,=WB4MNF,=WB5ZDH,=WB5ZOV,=WB6CVJ, + =WB6PIO,=WB6PJT,=WB6SAA,=WB8NCD,=WB9SMM,=WC6B,=WD0FTF,=WD0LFN,=WD6EZL,=WD6GHJ,=WD8LIB,=WD8OBO, + =WH2Y,=WH7K,=WU0H,=WV0Z,=WV6K,=WX7G,=WY6F; Kure Island: 31: 61: OC: 29.00: 178.00: 10.0: KH7K: AH7K,KH7K,NH7K,WH7K; American Samoa: 32: 62: OC: -14.32: 170.78: 11.0: KH8: - AH8,KH8,NH8,WH8,=AB9OH,=AF7MN,=KD8TFY,=KM4YJH,=KS6EL,=KS6FS,=W3HG,=WH6BAR,=WL7BMP; + AH8,KH8,NH8,WH8,=AB9OH,=AF7MN,=KD8TFY,=KH0WF,=KM4YJH,=KS6EL,=KS6FS,=W3HG,=WH6BAR,=WL7BMP; Swains Island: 32: 62: OC: -11.05: 171.25: 11.0: KH8/s: =KH6BK/KH8,=KH8/WH7S,=KH8S/K3UY,=KH8S/NA6M,=KH8SI,=NH8S; Wake Island: 31: 65: OC: 19.28: -166.63: -12.0: KH9: @@ -1647,70 +1681,73 @@ Wake Island: 31: 65: OC: 19.28: -166.63: -12.0: KH9: Alaska: 01: 01: NA: 61.40: 148.87: 8.0: KL: AL,KL,NL,WL,=AA0NN,=AA8FY,=AB0IC,=AB0WK,=AB5JB,=AB7YB,=AB7YO,=AB8XX,=AB9OM,=AC0CW,=AC9QX,=AD0DK, =AD0FQ,=AD0ZL,=AD3BJ,=AD6GC,=AD7MF,=AD7VV,=AE1DJ,=AE4QH,=AE5CP,=AE5EX,=AE5FN,=AE5IR,=AE7ES,=AE7KS, - =AE7SB,=AF7FV,=AG5LN,=AG5OF,=AH0AH,=AH0H,=AJ4ZI,=K0AZZ,=K0BHC,=K1BZD,=K1MAT,=K2ICW,=K2NPS,=K3JMI, - =K4ETC,=K4HOE,=K4RND,=K4WPK,=K5DOW,=K5HL,=K5RD,=K5RSO,=K5RZW,=K5TDN,=K5UBS,=K6ANE,=K6GKW,=K7EJM, - =K7GRW,=K7LOP,=K7MVX,=K7OCL,=K7RDR,=K7UNX,=K7ZOA,=K8IEL,=K8OUA,=K9DUG,=K9WUV,=KA0SIM,=KA0YPV, - =KA1NCN,=KA2TJZ,=KA2ZSD,=KA6UGT,=KA7ETQ,=KA7HOX,=KA7JOR,=KA7TMU,=KA7TOM,=KA7UKN,=KA7VCR,=KA7YEY, - =KA9GYQ,=KB0APK,=KB0LOW,=KB0TSU,=KB0UGE,=KB0UVK,=KB1CRT,=KB1FCX,=KB1KLH,=KB1PHP,=KB1QCD,=KB1QCE, - =KB1SYV,=KB1WQL,=KB2JWV,=KB2ZME,=KB3CYB,=KB3JFK,=KB3NCR,=KB4DX,=KB5DNT,=KB5HEV,=KB5UWU,=KB6DKJ, - =KB7AMA,=KB7BNG,=KB7DEL,=KB7FXJ,=KB7IBI,=KB7JA,=KB7LJZ,=KB7LON,=KB7PHT,=KB7QLB,=KB7RXZ,=KB7SIQ, - =KB7UBH,=KB7VFZ,=KB7YEC,=KB7ZVZ,=KB8QKR,=KB8SBG,=KB8TEW,=KB8VYJ,=KB9MWG,=KB9RWE,=KB9RWJ,=KB9YGR, - =KC0ATI,=KC0CWG,=KC0CYR,=KC0EF,=KC0GHH,=KC0NSV,=KC0OKQ,=KC0PSZ,=KC0TK,=KC0TZL,=KC0UYK,=KC0VDN, - =KC0WSG,=KC0YSW,=KC1DL,=KC2BYX,=KC2GVS,=KC2HRV,=KC2KMU,=KC2OJP,=KC2PCV,=KC2PIO,=KC3DBK,=KC4MXQ, - =KC4MXR,=KC5BNN,=KC5CHO,=KC5DJA,=KC5KIG,=KC5LKF,=KC5LKG,=KC5QPJ,=KC5THY,=KC5YIB,=KC5YOX,=KC5ZAA, - =KC6RJW,=KC7BUL,=KC7COW,=KC7ENM,=KC7FWK,=KC7GSO,=KC7HJM,=KC7HPF,=KC7IKE,=KC7IKF,=KC7INC,=KC7MIJ, - =KC7MPY,=KC7MRO,=KC7OQZ,=KC7PLJ,=KC7PLQ,=KC7RCP,=KC7TYT,=KC7UZY,=KC7WOA,=KC7YZR,=KC8BKP,=KC8GKK, - =KC8NMN,=KC8NOY,=KC8WWS,=KC8YIV,=KC9CMY,=KC9HIK,=KC9VLD,=KD0CLU,=KD0CZC,=KD0DHU,=KD0FJG,=KD0JJB, - =KD0NSG,=KD0VAK,=KD0VAL,=KD0VGF,=KD0ZOD,=KD2CTE,=KD2GKT,=KD4EYW,=KD4MEY,=KD4QJL,=KD5DWV,=KD5GAL, - =KD5QPD,=KD5RVD,=KD5WCF,=KD5WEV,=KD6DLB,=KD6RVY,=KD6YKS,=KD7APU,=KD7AWK,=KD7BBX,=KD7BGP,=KD7DIG, - =KD7DUQ,=KD7FGL,=KD7FUL,=KD7GFG,=KD7HXF,=KD7KRK,=KD7MGO,=KD7QAR,=KD7SIX,=KD7TWB,=KD7UAG,=KD7VOI, - =KD7VXE,=KD7ZTJ,=KD8BVD,=KD8DDY,=KD8GEL,=KD8GMS,=KD8JOU,=KD8LNA,=KD8WMX,=KD9TK,=KE0DYM,=KE0KKI, - =KE4DGR,=KE4MQD,=KE4YEI,=KE4YLG,=KE5CVD,=KE5CVT,=KE5DQV,=KE5FOC,=KE5GEB,=KE5HHR,=KE5JHS,=KE5JTB, - =KE5NLG,=KE5QDI,=KE5QDJ,=KE5QDK,=KE5VPO,=KE5ZRK,=KE5ZUM,=KE6DLM,=KE6DUJ,=KE6DXH,=KE6IPM,=KE6SYD, - =KE6TCE,=KE6VUB,=KE7DFO,=KE7ELL,=KE7EOP,=KE7EPZ,=KE7FNC,=KE7FXM,=KE7GOE,=KE7HMJ,=KE7KAT,=KE7KYU, - =KE7TRX,=KE8RO,=KF4JET,=KF4PLR,=KF4TBD,=KF4YFD,=KF5FJQ,=KF5HFB,=KF5HJC,=KF5NDT,=KF5NHR,=KF5YYK, - =KF6AWG,=KF6AXS,=KF6BMF,=KF6BOV,=KF6EJR,=KF6GNM,=KF6IAO,=KF6ILC,=KF6IOT,=KF6LGK,=KF6MFK,=KF6QOJ, - =KF6RMG,=KF6RPC,=KF6SHS,=KF6TGR,=KF6UWT,=KF7LEX,=KF7LUA,=KF7PCJ,=KF7PFT,=KF7PSS,=KF7PUQ,=KF7UFY, - =KF7VBO,=KF8ZB,=KG2IA,=KG4BBX,=KG4NBL/P,=KG4TJS,=KG4WNZ,=KG5EQN,=KG5GDF,=KG5GTD,=KG5JQC,=KG5MIB, - =KG6DTI,=KG6MBC,=KG6RJE,=KG6TAL,=KG7CUR,=KG7DVI,=KG7GJL,=KG7JVJ,=KG7OQC,=KG7SEQ,=KG7TGE,=KH0NF, - =KH0NG,=KH0RF,=KH2YN,=KH7BW,=KH7DA,=KI4COG,=KI4ERC,=KI4GAG,=KI4GCF,=KI4GDI,=KI4NGY,=KI4NVI, - =KI4SET,=KI4SOM,=KI6BGR,=KI6DES,=KI6HGW,=KI7COR,=KI7PZ,=KI8JT,=KJ4HEW,=KJ4IAQ,=KJ4PSV,=KJ4WDI, - =KJ4ZWI,=KJ6KRG,=KJ6ZSX,=KJ7IR,=KK4AMV,=KK4CLS,=KK4LRE,=KK4QXE,=KK4RYG,=KK4WWH,=KK4WWI,=KK6IUY, - =KK6PGV,=KK7I,=KK7IV,=KK7STL,=KL7D/M,=KL7NC/IMD,=KM4AGL,=KM4KWS,=KM4KX,=KM4NIC,=KM4OE,=KM4PJH, - =KM4TJI,=KN8IVE,=KR4WV,=KV3X,=KW1W,=KY7J,=KZ6HJC,=N0GDT,=N0GDU,=N0GLI,=N0HJT,=N0HZF,=N0LHN,=N0SN, - =N0SUB,=N0WXJ,=N0XKY,=N0XS,=N0ZKV,=N1HUT,=N1KDQ,=N1KTI,=N1NDA,=N1NJS,=N1QFE,=N1TX,=N2CXH,=N2SHO, - =N2TJY,=N2YZW,=N3QEH,=N4AVX,=N4CM,=N4HCJ,=N4HZU,=N4NAV,=N5CSO,=N5UKX,=N5WPR,=N6BSC,=N6CVV,=N6CZU, - =N6JM,=N7BUO,=N7FCT,=N7HER,=N7HQK,=N7IA,=N7JUX,=N7MGT,=N7MTG,=N7PHB,=N7QAN,=N7TBU,=N7UTV,=N7UWT, - =N7XNM,=N7YKY,=N7YQS,=N7ZYS,=N8DDY,=N8EX,=N8KCJ,=N8SUG,=N9AIG,=N9FB,=N9YD,=NA7WM,=NC4OI,=NE7EK, - =NE9V,=NH2GZ,=NH7UO,=NJ7H,=NN4NN,=NP4FU,=NW4G,=NW7F,=W0FJN,=W0RWS,=W0UZJ,=W1LYD,=W1RSC,=W1ZKA, - =W2DLS,=W2KRZ,=W3JPN,=W4AUL,=W4BMR,=W4LS,=W4RSB,=W5JKT,=W6DDP,=W6GTE,=W6ROW,=W7APM,=W7DDG,=W7EIK, - =W7JMR,=W7NUT,=W7PWA,=W7RAZ,=W7ROS,=W7WEZ,=W7ZWT,=W8MDD,=W8PVZ,=W8TCX,=W9ITU,=W9JMC,=WA0JS, - =WA1FVJ,=WA2BGL,=WA2BIW,=WA6GFS,=WA7B,=WA7PXH,=WA7USX,=WA7YXF,=WB0CMZ,=WB1GZL,=WB1ILS,=WB6COP, - =WB7QWM,=WB7TYK,=WB9JZL,=WD6CET,=WH6CYY,=WH6DPL,=WH6DX,=WH7AK,=WJ8M,=WP4IYI,=WT5T,=WX1NCC; + =AE7SB,=AF7FV,=AG5LN,=AG5OF,=AH0AH,=AH0H,=AJ4ZI,=K0AZZ,=K0BHC,=K1BZD,=K1KAO,=K1MAT,=K2ICW,=K2NPS, + =K3JMI,=K4DRC,=K4ETC,=K4HOE,=K4RND,=K4WPK,=K5DOW,=K5HL,=K5RD,=K5RSO,=K5RZW,=K5TDN,=K6ANE,=K6GKW, + =K7EJM,=K7GRW,=K7LOP,=K7MVX,=K7OCL,=K7RDR,=K7SGA,=K7UNX,=K7ZOA,=K8IEL,=K8OUA,=K9DUG,=K9WUV, + =KA0SIM,=KA0YPV,=KA1NCN,=KA2TJZ,=KA2ZSD,=KA6UGT,=KA7ETQ,=KA7HOX,=KA7JOR,=KA7TMU,=KA7TOM,=KA7UKN, + =KA7VCR,=KA7YEY,=KA9GYQ,=KB0APK,=KB0LOW,=KB0TSU,=KB0UGE,=KB0UVK,=KB1CRT,=KB1FCX,=KB1KLH,=KB1PHP, + =KB1QCD,=KB1QCE,=KB1SYV,=KB1WQL,=KB2JWV,=KB2ZME,=KB3CYB,=KB3JFK,=KB3NCR,=KB3VQE,=KB4DX,=KB5DNT, + =KB5HEV,=KB5UWU,=KB6DKJ,=KB7AMA,=KB7BNG,=KB7DEL,=KB7FXJ,=KB7IBI,=KB7JA,=KB7LJZ,=KB7LON,=KB7PHT, + =KB7QLB,=KB7RXZ,=KB7SIQ,=KB7UBH,=KB7VFZ,=KB7YEC,=KB7ZVZ,=KB8QKR,=KB8SBG,=KB8TEW,=KB8VYJ,=KB9MWG, + =KB9RWE,=KB9RWJ,=KB9YGR,=KC0ATI,=KC0CWG,=KC0CYR,=KC0EF,=KC0GHH,=KC0LLL,=KC0NSV,=KC0OKQ,=KC0PSZ, + =KC0TK,=KC0TZL,=KC0UYK,=KC0VDN,=KC0WSG,=KC0YSW,=KC1DL,=KC1KPL,=KC2BYX,=KC2GVS,=KC2HRV,=KC2KMU, + =KC2OJP,=KC2PCV,=KC2PIO,=KC3DBK,=KC4MXQ,=KC4MXR,=KC5BNN,=KC5CHO,=KC5DJA,=KC5KIG,=KC5LKF,=KC5LKG, + =KC5QPJ,=KC5THY,=KC5YIB,=KC5YOX,=KC5ZAA,=KC6RJW,=KC7BUL,=KC7COW,=KC7ENM,=KC7FWK,=KC7GSO,=KC7HJM, + =KC7HPF,=KC7IKE,=KC7IKF,=KC7INC,=KC7MIJ,=KC7MPY,=KC7MRO,=KC7OQZ,=KC7PLJ,=KC7PLQ,=KC7RCP,=KC7TYT, + =KC7UZY,=KC7WOA,=KC7YZR,=KC8GKK,=KC8MVW,=KC8NMN,=KC8NOY,=KC8WWS,=KC8YIV,=KC9CMY,=KC9HIK,=KC9VLD, + =KD0CLU,=KD0CZC,=KD0DHU,=KD0FJG,=KD0IXU,=KD0JJB,=KD0NSG,=KD0VAK,=KD0VAL,=KD0VGF,=KD0ZOD,=KD2CTE, + =KD2GKT,=KD4EYW,=KD4MEY,=KD4QJL,=KD5DNA,=KD5DWV,=KD5GAL,=KD5QPD,=KD5RVD,=KD5WCF,=KD5WEV,=KD5WYP, + =KD6DLB,=KD6RVY,=KD6YKS,=KD7APU,=KD7AWK,=KD7BBX,=KD7BGP,=KD7DIG,=KD7DUQ,=KD7FGL,=KD7FUL,=KD7GFG, + =KD7HXF,=KD7KRK,=KD7MGO,=KD7QAR,=KD7SIX,=KD7TWB,=KD7UAG,=KD7VOI,=KD7VXE,=KD7ZTJ,=KD8BVD,=KD8DDY, + =KD8GEL,=KD8GMS,=KD8JOU,=KD8LNA,=KD8WMX,=KD9TK,=KE0DYM,=KE0KKI,=KE4DGR,=KE4MQD,=KE4YEI,=KE4YLG, + =KE5CVD,=KE5CVT,=KE5DQV,=KE5FOC,=KE5GEB,=KE5HHR,=KE5JHS,=KE5JTB,=KE5NLG,=KE5QDI,=KE5QDJ,=KE5QDK, + =KE5VPO,=KE5ZRK,=KE5ZUM,=KE6DLM,=KE6DUJ,=KE6DXH,=KE6IPM,=KE6SYD,=KE6TCE,=KE6VUB,=KE7DFO,=KE7ELL, + =KE7EOP,=KE7EPZ,=KE7FNC,=KE7FXM,=KE7GOE,=KE7HMJ,=KE7KYU,=KE7TRX,=KE8RO,=KF3L,=KF4JET,=KF4PLR, + =KF4TBD,=KF4YFD,=KF5CVM,=KF5FJQ,=KF5HFB,=KF5HJC,=KF5NDT,=KF5NHR,=KF5YYK,=KF6AWG,=KF6AXS,=KF6BMF, + =KF6BOV,=KF6EJR,=KF6GNM,=KF6IAO,=KF6ILC,=KF6IOT,=KF6LGK,=KF6MFK,=KF6QOJ,=KF6RMG,=KF6RPC,=KF6SHS, + =KF6TGR,=KF6UWT,=KF7CXJ,=KF7GKY,=KF7LEX,=KF7LUA,=KF7PCJ,=KF7PFT,=KF7PSS,=KF7PUQ,=KF7UFY,=KF7VBO, + =KF8ZB,=KG2IA,=KG4BBX,=KG4NBL/P,=KG4TJS,=KG4WNZ,=KG5EQN,=KG5GDF,=KG5GTD,=KG5JQC,=KG5MIB,=KG5MIO, + =KG6DTI,=KG6MBC,=KG6RJE,=KG6TAL,=KG7CUR,=KG7DVI,=KG7GJL,=KG7JVJ,=KG7OQC,=KG7OUF,=KG7SEQ,=KG7TGE, + =KH0NF,=KH0NG,=KH0RF,=KH2YN,=KH7BW,=KH7DA,=KI4COG,=KI4ERC,=KI4GAG,=KI4GCF,=KI4GDI,=KI4NGY,=KI4NVI, + =KI4SET,=KI4SOM,=KI6BGR,=KI6DES,=KI6HGW,=KI6YXZ,=KI7COR,=KI7PZ,=KI8JT,=KJ4HEW,=KJ4IAQ,=KJ4PSV, + =KJ4WDI,=KJ4WIQ,=KJ4ZWI,=KJ6DCH,=KJ6KRG,=KJ6ZSX,=KJ7IR,=KK4AMV,=KK4CLS,=KK4LRE,=KK4QXE,=KK4RYG, + =KK4WWH,=KK4WWI,=KK6IUY,=KK6PGV,=KK7I,=KK7IV,=KK7STL,=KL7D/M,=KL7NC/IMD,=KM4AGL,=KM4KWS,=KM4KX, + =KM4NIC,=KM4OE,=KM4PJH,=KM4TJI,=KM6NOL,=KN4HGD,=KN8IVE,=KR4WV,=KV3X,=KW1W,=KY7J,=KZ6HJC,=N0GDT, + =N0GDU,=N0GLI,=N0HJT,=N0HYI,=N0HZF,=N0JEN,=N0LHN,=N0SN,=N0SUB,=N0WXJ,=N0XKY,=N0XS,=N0ZKV,=N1HEN, + =N1HUT,=N1KDQ,=N1KTI,=N1NDA,=N1NJS,=N1QFE,=N1TX,=N2CXH,=N2SHO,=N2TJY,=N2YZW,=N3QEH,=N4AVX,=N4CM, + =N4HCJ,=N4HZU,=N4NAV,=N5CSO,=N5UKX,=N5WPR,=N6BSC,=N6CVV,=N6CZU,=N6JM,=N6ZZX,=N7BUO,=N7DBN,=N7FCT, + =N7HER,=N7HQK,=N7IA,=N7JUX,=N7MGT,=N7MTG,=N7PHB,=N7QAN,=N7TBU,=N7UTV,=N7UWT,=N7XNM,=N7YKY,=N7YQS, + =N8DDY,=N8EX,=N8JKB,=N8KCJ,=N8SUG,=N9AIG,=N9FB,=N9YD,=NA7WM,=NC4OI,=NE7EK,=NH2GZ,=NH7UO,=NJ7H, + =NM0H,=NN4NN,=NP4FU,=NW4G,=NW7F,=W0EZM,=W0FJN,=W0RWS,=W0UZJ,=W1LYD,=W1RSC,=W1ZKA,=W2DLS,=W2KRZ, + =W3JPN,=W3MKG,=W4AUL,=W4BMR,=W4RSB,=W5JKT,=W6DDP,=W6GTE,=W6ROW,=W7APM,=W7DDG,=W7EIK,=W7JMR,=W7PWA, + =W7RAZ,=W7ROS,=W7WEZ,=W7ZWT,=W8MDD,=W8PVZ,=W8TCX,=W9ITU,=W9JMC,=WA0JS,=WA1FVJ,=WA2BGL,=WA2BIW, + =WA6GFS,=WA7B,=WA7PXH,=WA7USX,=WA7YXF,=WB0CMZ,=WB1GZL,=WB1ILS,=WB6COP,=WB7TYK,=WB9JZL,=WD6CET, + =WH6CYY,=WH6DPL,=WH6DX,=WH7AK,=WJ8M,=WP4IYI,=WT5T,=WX1NCC; Navassa Island: 08: 11: NA: 18.40: 75.00: 5.0: KP1: KP1,NP1,WP1; US Virgin Islands: 08: 11: NA: 17.73: 64.80: 4.0: KP2: KP2,NP2,WP2,=AC7FX,=AJ2O,=K5KFL,=K5TP,=K8RF,=KA7KDU,=KB1MDZ,=KB1ZTY,=KB3ZUD,=KB9ALR,=KC9MCN, - =KD4SGB,=KD5QJN,=KF2HC,=KF4CGR,=KF4MSI,=KG4SZC,=KG5KHO,=KH2XQ,=KH2XR,=KI4FOE,=KI6BLD,=KJ6IR, - =KL7NZ,=KR7O/R,=KV4/W2KW,=KV4AD,=KV4BA,=KV4BT,=KV4BW,=KV4CF,=KV4CQ/P,=KV4DN,=KV4EY,=KV4FZ,=KV4HR, - =KV4IH,=KV4JC,=KV4KW,=N1TKK,=N1VKI,=W0AIH/KV4,=W0YNY,=W2AZK,=W2KW/KV4,=W3K/KD2CLB,=W4LIS,=WA4HLB, - =WB2KQW,=WB4WFU,=WD8AHQ,=WI7C; + =KD4SGB,=KD5QJN,=KF2HC,=KF4CGR,=KF4MSI,=KG4SZC,=KG5KHO,=KG6KVR,=KH2XQ,=KH2XR,=KI4FOE,=KI6BLD, + =KJ6IR,=KL7NZ,=KR7O/R,=KV4/W2KW,=KV4AD,=KV4BA,=KV4BT,=KV4BW,=KV4CF,=KV4CQ/P,=KV4DN,=KV4EY,=KV4FZ, + =KV4HR,=KV4IH,=KV4JC,=KV4KW,=N1TKK,=N1VKI,=W0AIH/KV4,=W0YNY,=W2AZK,=W2KW/KV4,=W3K/KD2CLB,=W4LIS, + =WA4HLB,=WB2KQW,=WB4WFU,=WD8AHQ,=WI7C; Puerto Rico: 08: 11: NA: 18.18: 66.55: 4.0: KP4: - KP3,KP4,NP3,NP4,WP3,WP4,=AA2ZN,=AB2DR,=AF4OU,=AF5IZ,=AG4CD,=AI4EZ,=K1NDN,=K4C/LH,=K4PFH,=K5YJR, - =K6BOT,=K9JOS,=KA2GNG,=KA2MBR,=KA2YGB,=KA7URH,=KA9UTY,=KB0AQB,=KB0TEP,=KB1IJU,=KB1KDP,=KB1RUQ, - =KB1TUA,=KB1UEK,=KB1UZV,=KB1ZKF,=KB2ALR,=KB2CIE,=KB2KWB,=KB2MMX,=KB2NMT,=KB2NYN,=KB2OIF,=KB2OMN, - =KB2OPM,=KB2RYP,=KB2TID,=KB2VHY,=KB2WKT,=KB2YKJ,=KB3BPK,=KB3BTN,=KB3LUV,=KB3SBO,=KB8ZVP,=KB9OWX, - =KB9RZD,=KB9YVE,=KB9YVF,=KC1CRV,=KC1CUF,=KC1DRV,=KC1IHB,=KC1IHO,=KC1JLY,=KC2BZZ,=KC2CTM,=KC2EMM, - =KC2ERU,=KC2JNE,=KC2LET,=KC2TE,=KC2UXP,=KC3GEO,=KC5DKT,=KC8IRI,=KD2KPC,=KD2VQ,=KD4TVS,=KD5DVV, - =KD5PKH,=KD9GIZ,=KE0AYJ,=KE0GFK,=KE0SH,=KE1MA,=KE4GGD,=KE4GYA,=KE4SKH,=KE4THL,=KE4WUE,=KE5LNG, - =KF4KPO,=KF4ZDB,=KF6OGJ,=KG4IRC,=KG4IVO,=KG4VCC,=KG5AFY,=KH2RU,=KH4AA,=KI4LRJ,=KI4WOA,=KI4WOB, - =KJ4LOZ,=KJ4UPN,=KJ6OV,=KK4AOZ,=KK4DCX,=KK4EBE,=KK4PHB,=KM4VDZ,=KM4WGI,=KM4YBN,=KM4YSR,=KM4ZJW, - =KM6CTO,=KN4AWH,=KN4GNO,=KN4IBD,=KN4IDV,=KN4IGP,=KN4ILO,=KN4INP,=KN4JCC,=KN4KPX,=KN4KPY,=KN4MNT, - =KN4NLZ,=KN4ODN,=KN4QBT,=KN4QZZ,=KP2H,=KP2Z,=KP3CW/SKP,=KP3RE/LGT,=KP3RE/LH,=KP3RE/LT,=KP4ES/L, - =KP4ES/LGT,=KP4ES/LH,=KP4FD/IARU,=KP4FRD/LH,=KP4MD/P,=KP4VP/LH,=N0XAR,=N1CN,=N1HRV,=N1JFL,=N1QVU, - =N1SCD,=N1SZM,=N1VCW,=N1YAY,=N1ZJC,=N2KKN,=N2KUE,=N2PGO,=N3JAM,=N3VIJ,=N3YUB,=N3ZII,=N4JZD,=N4LER, - =N4UK,=N6NVD,=N6RHF,=NB0G,=NP3M/LH,=NP4VO/LH,=W1AW/PR,=W3YW,=W6WAW,=W9JS,=WA2RVA,=WB2HMY,=WB5YOF, - =WB7ADC,=WB7VVV,=WD4LOL,=WP4L/TP,=WR8Z; + KP3,KP4,NP3,NP4,WP3,WP4,=AA0WX,=AA2ZN,=AB2DR,=AF4OU,=AF5IZ,=AG4CD,=AI4EZ,=K1NDN,=K4C/LH,=K4LCR, + =K4PFH,=K5YJR,=K6BOT,=K9JOS,=KA2GNG,=KA2MBR,=KA2YGB,=KA3ZGQ,=KA7URH,=KA9UTY,=KB0AQB,=KB0JRR, + =KB0TEP,=KB1IJU,=KB1KDP,=KB1RUQ,=KB1TUA,=KB1UEK,=KB1UZV,=KB1ZKF,=KB2ALR,=KB2CIE,=KB2KWB,=KB2MMX, + =KB2NMT,=KB2NYN,=KB2OIF,=KB2OMN,=KB2OPM,=KB2QQK,=KB2RYP,=KB2TID,=KB2VHY,=KB2WKT,=KB2YKJ,=KB3BPK, + =KB3BTN,=KB3LUV,=KB3SBO,=KB8ZVP,=KB9OWX,=KB9RZD,=KB9YVE,=KB9YVF,=KC1CRV,=KC1CUF,=KC1DRV,=KC1IHB, + =KC1IHO,=KC1JLY,=KC1KZI,=KC2BZZ,=KC2CJL,=KC2CTM,=KC2EMM,=KC2ERU,=KC2JNE,=KC2LET,=KC2TE,=KC2UXP, + =KC2VCR,=KC3GEO,=KC5DKT,=KC8BFN,=KC8IRI,=KD2KPC,=KD2VQ,=KD4TVS,=KD5DVV,=KD5PKH,=KD9GIZ,=KD9MRY, + =KE0AYJ,=KE0GFK,=KE0SH,=KE1MA,=KE3WW,=KE4GGD,=KE4GYA,=KE4SKH,=KE4THL,=KE4WUE,=KE5LNG,=KF4KPO, + =KF4ZDB,=KF6OGJ,=KG4GYO,=KG4IRC,=KG4IVO,=KG4VCC,=KG5AFY,=KH2RU,=KH4AA,=KI4LRJ,=KI4WOA,=KI4WOB, + =KJ4KZN,=KJ4LOZ,=KJ4UPN,=KJ6OV,=KK4AOZ,=KK4DCX,=KK4EBE,=KK4PHB,=KM4VDZ,=KM4WGI,=KM4YBN,=KM4YSR, + =KM4ZJW,=KM6CTO,=KN4AWH,=KN4GNO,=KN4IBD,=KN4IDV,=KN4IGP,=KN4ILO,=KN4INP,=KN4JCC,=KN4KPX,=KN4KPY, + =KN4MNT,=KN4NLZ,=KN4ODN,=KN4QBT,=KN4QZZ,=KN4REC,=KN4SKZ,=KN4TNC,=KN4UAN,=KP2H,=KP2Z,=KP3CW/SKP, + =KP3RE/LGT,=KP3RE/LH,=KP3RE/LT,=KP4ES/L,=KP4ES/LGT,=KP4ES/LH,=KP4FD/IARU,=KP4FRD/LH,=KP4MD/P, + =KP4VP/LH,=N0XAR,=N1CN,=N1HRV,=N1JFL,=N1QVU,=N1SCD,=N1SZM,=N1VCW,=N1YAY,=N1ZJC,=N2KKN,=N2KUE, + =N2PGO,=N3JAM,=N3VIJ,=N3YUB,=N3ZII,=N4CIE,=N4JZD,=N4LER,=N4UK,=N6NVD,=N6RHF,=NB0G,=NP3M/LH, + =NP4VO/LH,=W1AW/PR,=W6WAW,=W9JS,=WA2RVA,=WB2HMY,=WB5YOF,=WB7ADC,=WB7VVV,=WD4LOL,=WP4L/TP,=WR8Z; Desecheo Island: 08: 11: NA: 18.08: 67.88: 4.0: KP5: KP5,NP5,WP5; Norway: 14: 18: EU: 61.00: -9.00: -1.0: LA: @@ -1736,55 +1773,55 @@ Argentina: 13: 14: SA: -34.80: 65.92: 3.0: LU: =LU1EST/D,=LU1EUU/D,=LU1EXU/D,=LU1EY/D,=LU1HBD/D,=LU1HLH/D,=LU1KCQ/D,=LU1UAG/D,=LU1VDF/D, =LU1VOF/D,=LU1XWC/E,=LU1XZ/D,=LU1YY/D,=LU2AAS/D,=LU2AEZ/D,=LU2AFE/D,=LU2AGQ/D,=LU2AHB/D,=LU2ALE/D, =LU2AMM/D,=LU2AVG/D,=LU2AVW/D,=LU2BN/D,=LU2BOE/D,=LU2BPM/D,=LU2CDE/D,=LU2CDO/D,=LU2CHP/D,=LU2CM/D, - =LU2DAR/D,=LU2DB/D,=LU2DG/D,=LU2DHM/D,=LU2DJC/D,=LU2DJL/D,=LU2DKN/D,=LU2DPW/D,=LU2DRT/D,=LU2DT/D, - =LU2DT/D/LH,=LU2DT/LGT,=LU2DT/LH,=LU2DVF/D,=LU2ED/D,=LU2EDC/D,=LU2EE/D,=LU2EE/E,=LU2EGA/D, - =LU2EGI/D,=LU2EGP/D,=LU2EHA/D,=LU2EIT/D,=LU2EJL/D,=LU2EK/D,=LU2ELT/D,=LU2EMQ/D,=LU2ENG/D, - =LU2ENH/D,=LU2ERC/D,=LU2FGD/D,=LU2FNH/D,=LU2HOD/D,=LU2JFC/D,=LU2VDV/D,=LU2YF/D,=LU3AAL/D, - =LU3ADC/D,=LU3AJL/D,=LU3AOI/D,=LU3ARE/D,=LU3ARM/D,=LU3AYE/D,=LU3CA/D,=LU3CM/D,=LU3CRA/D,=LU3CT/D, - =LU3DAT/D,=LU3DAT/E,=LU3DC/D,=LU3DEY/D,=LU3DFD/D,=LU3DH/D,=LU3DHF/D,=LU3DJI/D,=LU3DK/D,=LU3DLF/D, - =LU3DMZ/D,=LU3DO/D,=LU3DOC/D,=LU3DP/D,=LU3DPH/D,=LU3DQJ/D,=LU3DR/D,=LU3DRP/D,=LU3DXG/D,=LU3DXI/D, - =LU3DY/D,=LU3DYN/D,=LU3DZO/D,=LU3EBS/D,=LU3ED/D,=LU3EDU/D,=LU3EFL/D,=LU3EJ/L,=LU3EJD/D,=LU3ELR/D, - =LU3EMB/D,=LU3EOU/D,=LU3EP/D,=LU3ERU/D,=LU3ES/D,=LU3ESY/D,=LU3EZA/D,=LU3FCI/D,=LU3HKA/D,=LU4AA/D, - =LU4AAO/D,=LU4AAO/E,=LU4ACA/D,=LU4AJC/D,=LU4BAN/D,=LU4BR/D,=LU4CMF/D,=LU4DBL/D,=LU4DBP/D, - =LU4DBT/D,=LU4DBV/D,=LU4DCE/D,=LU4DCY/D,=LU4DGC/D,=LU4DHA/D,=LU4DHC/D,=LU4DHE/D,=LU4DIS/D, - =LU4DK/D,=LU4DLJ/D,=LU4DLL/D,=LU4DLN/D,=LU4DMI/D,=LU4DPB/D,=LU4DQ/D,=LU4DRC/D,=LU4DRH/D,=LU4DRH/E, - =LU4DVD/D,=LU4EAE/D,=LU4EET/D,=LU4EGP/D,=LU4EHP/D,=LU4EJ/D,=LU4EL/D,=LU4ELE/D,=LU4EOU/D,=LU4ERS/D, - =LU4ESP/D,=LU4ETD/D,=LU4ETN/D,=LU4EV/D,=LU4HSA/D,=LU4HTD/D,=LU4MA/D,=LU4UWZ/D,=LU4UZW/D,=LU4VEN/D, - =LU4VSD/D,=LU4WAP/D,=LU5AHN/D,=LU5ALS/D,=LU5AM/D,=LU5ANL/D,=LU5AQV/D,=LU5ARS/D,=LU5ASA/D, - =LU5AVD/D,=LU5BDS/D,=LU5BE/D,=LU5BTL/D,=LU5CBA/D,=LU5CRE/D,=LU5DA/D,=LU5DA/E,=LU5DAS/D,=LU5DCO/D, - =LU5DDH/D,=LU5DEM/D,=LU5DF/D,=LU5DFR/D,=LU5DFT/D,=LU5DGG/D,=LU5DGR/D,=LU5DHE/D,=LU5DIT/D, - =LU5DJE/D,=LU5DKE/D,=LU5DLH/D,=LU5DLT/D,=LU5DLZ/D,=LU5DMI/D,=LU5DMP/D,=LU5DMR/D,=LU5DQ/D, - =LU5DRV/D,=LU5DSH/D,=LU5DSM/D,=LU5DT/D,=LU5DTB/D,=LU5DTF/D,=LU5DUC/D,=LU5DVB/D,=LU5DWS/D, - =LU5DYT/D,=LU5EAO/D,=LU5EC/D,=LU5ED/D,=LU5EDS/D,=LU5EFG/D,=LU5EH/D,=LU5EHC/D,=LU5EJL/D,=LU5EM/D, - =LU5EP/D,=LU5EW/D,=LU5FZ/D,=LU5FZ/E,=LU5JAH/D,=LU5JIB/D,=LU5OD/D,=LU5VAS/D,=LU5VAT/D,=LU5XP/D, - =LU6AER/D,=LU6CN/D,=LU6DAX/D,=LU6DBL/D,=LU6DC/D,=LU6DCT/D,=LU6DDC/D,=LU6DG/D,=LU6DIE/D,=LU6DIO/D, - =LU6DKT/D,=LU6DL/D,=LU6DM/D,=LU6DO/D,=LU6DRD/D,=LU6DRD/E,=LU6DRN/D,=LU6DRR/D,=LU6DSA/D,=LU6DTB/D, - =LU6EAG/D,=LU6EC/D,=LU6EDC/D,=LU6EE/D,=LU6EEG/D,=LU6EGO/D,=LU6EI/D,=LU6EJJ/D,=LU6EKL/D,=LU6ELP/D, - =LU6EMM/D,=LU6ENA/D,=LU6EPE/D,=LU6EPR/D,=LU6EPR/E,=LU6EQV/D,=LU6EU/D,=LU6EVD/D,=LU6EWR/D, - =LU6EXD/D,=LU6HBB/D,=LU6JJ/D,=LU6UAL/D,=LU6UO/D,=LU6UVI/D,=LU6XQ/D,=LU7AA/D,=LU7AC/D,=LU7ADC/D, - =LU7ADN/D,=LU7ART/D,=LU7AVW/D,=LU7BSN/D,=LU7BTO/D,=LU7BTO/E,=LU7CAW/D,=LU7CP/D,=LU7DAC/D, - =LU7DAF/D,=LU7DAR/D,=LU7DBA/D,=LU7DBL/D,=LU7DCE/D,=LU7DD/D,=LU7DDC/D,=LU7DDO/D,=LU7DHG/D, - =LU7DJH/D,=LU7DLN/D,=LU7DNM/D,=LU7DOT/D,=LU7DP/D,=LU7DR/D,=LU7DS/D,=LU7DSC/D,=LU7DSS/D,=LU7DSU/D, - =LU7DSY/D,=LU7DTC/D,=LU7DZL/D,=LU7DZL/E,=LU7DZV/D,=LU7ECZ/D,=LU7EGY/D,=LU7EHL/D,=LU7EIA/D, - =LU7EJC/D,=LU7ELY/D,=LU7EMA/D,=LU7EMM/D,=LU7ENP/D,=LU7EO/D,=LU7EON/D,=LU7EPC/D,=LU7ETR/D, - =LU7HBL/D,=LU7HW/D,=LU7HZ/D,=LU7VCH/D,=LU8ABR/D,=LU8ACH/D,=LU8ADX/D,=LU8AE/D,=LU8ARI/D,=LU8ATM/D, - =LU8DAF/D,=LU8DCF/D,=LU8DCH/D,=LU8DCK/D,=LU8DCM/D,=LU8DIP/D,=LU8DIW/D,=LU8DJR/D,=LU8DLD/D, - =LU8DLT/D,=LU8DMD/D,=LU8DQ/D,=LU8DR/D,=LU8DRA/D,=LU8DRH/D,=LU8DRQ/D,=LU8DSJ/D,=LU8DTF/D,=LU8DUJ/D, - =LU8DVQ/D,=LU8DW/D,=LU8DWR/D,=LU8DX/D,=LU8DY/D,=LU8DZE/D,=LU8DZH/D,=LU8EAG/D,=LU8EAJ/D,=LU8EBJ/D, - =LU8EBJ/E,=LU8EBK/D,=LU8EBK/E,=LU8EC/D,=LU8ECF/D,=LU8ECF/E,=LU8EEM/D,=LU8EFF/D,=LU8EGC/D, - =LU8EGS/D,=LU8EHQ/D,=LU8EHQ/E,=LU8EHS/D,=LU8EHV/D,=LU8EKC/D,=LU8EMC/D,=LU8ERH/D,=LU8ETC/D, - =LU8EU/D,=LU8EXJ/D,=LU8EXN/D,=LU8FAU/D,=LU8VCC/D,=LU8VER/D,=LU9ACJ/D,=LU9AEA/D,=LU9AOS/D, - =LU9AUC/D,=LU9BRC/D,=LU9BSA/D,=LU9CGN/D,=LU9CLH/D,=LU9DA/D,=LU9DAA/D,=LU9DAD/D,=LU9DB/D,=LU9DE/D, - =LU9DEQ/D,=LU9DF/D,=LU9DGE/D,=LU9DKO/D,=LU9DMG/D,=LU9DO/D,=LU9DPD/D,=LU9DPI/D,=LU9DPZ/E,=LU9DSD/D, - =LU9DVO/D,=LU9EAG/D,=LU9ECE/D,=LU9EI/D,=LU9EIM/D,=LU9EJM/D,=LU9EJS/E,=LU9EJZ/D,=LU9ENH/D, - =LU9EOE/D,=LU9ERA/D,=LU9ESD/D,=LU9ESD/E,=LU9ESD/LH,=LU9EV/D,=LU9EV/E,=LU9EV/LH,=LU9EY/D,=LU9EYE/D, - =LU9EZX/D,=LU9HDR/D,=LU9HJV/D,=LU9HVR/D,=LU9USD/D,=LU9WM/D,=LV7E/D,=LW1DAL/D,=LW1DDX/D,=LW1DE/D, - =LW1DEN/D,=LW1DEW/D,=LW1DJ/D,=LW1DOG/D,=LW1DQQ/D,=LW1DVB/D,=LW1DXH/D,=LW1DXP/D,=LW1DYN/D, + =LU2CRV/D,=LU2DAR/D,=LU2DB/D,=LU2DG/D,=LU2DHM/D,=LU2DJC/D,=LU2DJL/D,=LU2DKN/D,=LU2DPW/D,=LU2DRT/D, + =LU2DT/D,=LU2DT/D/LH,=LU2DT/LGT,=LU2DT/LH,=LU2DVF/D,=LU2ED/D,=LU2EDC/D,=LU2EE/D,=LU2EE/E, + =LU2EGA/D,=LU2EGI/D,=LU2EGP/D,=LU2EHA/D,=LU2EIT/D,=LU2EJL/D,=LU2EK/D,=LU2ELT/D,=LU2EMQ/D, + =LU2ENG/D,=LU2ENH/D,=LU2ERC/D,=LU2FGD/D,=LU2FNH/D,=LU2HOD/D,=LU2JFC/D,=LU2VDV/D,=LU2YF/D, + =LU3AAL/D,=LU3ADC/D,=LU3AJL/D,=LU3AOI/D,=LU3ARE/D,=LU3ARM/D,=LU3AYE/D,=LU3CA/D,=LU3CM/D,=LU3CRA/D, + =LU3CT/D,=LU3DAT/D,=LU3DAT/E,=LU3DC/D,=LU3DEY/D,=LU3DFD/D,=LU3DH/D,=LU3DHF/D,=LU3DJI/D,=LU3DK/D, + =LU3DLF/D,=LU3DMZ/D,=LU3DO/D,=LU3DOC/D,=LU3DP/D,=LU3DPH/D,=LU3DQJ/D,=LU3DR/D,=LU3DRP/D,=LU3DRP/E, + =LU3DXG/D,=LU3DXI/D,=LU3DY/D,=LU3DYN/D,=LU3DZO/D,=LU3EBS/D,=LU3ED/D,=LU3EDU/D,=LU3EFL/D,=LU3EJ/L, + =LU3EJD/D,=LU3ELR/D,=LU3EMB/D,=LU3EOU/D,=LU3EP/D,=LU3ERU/D,=LU3ES/D,=LU3ESY/D,=LU3EZA/D,=LU3FCI/D, + =LU3HKA/D,=LU4AA/D,=LU4AAO/D,=LU4AAO/E,=LU4ACA/D,=LU4ADE/D,=LU4AJC/D,=LU4BAN/D,=LU4BR/D,=LU4CMF/D, + =LU4DBL/D,=LU4DBP/D,=LU4DBT/D,=LU4DBV/D,=LU4DCE/D,=LU4DCY/D,=LU4DGC/D,=LU4DHA/D,=LU4DHC/D, + =LU4DHE/D,=LU4DIS/D,=LU4DK/D,=LU4DLJ/D,=LU4DLL/D,=LU4DLN/D,=LU4DMI/D,=LU4DPB/D,=LU4DQ/D,=LU4DRC/D, + =LU4DRH/D,=LU4DRH/E,=LU4DVD/D,=LU4EAE/D,=LU4EET/D,=LU4EGP/D,=LU4EHP/D,=LU4EJ/D,=LU4EL/D,=LU4ELE/D, + =LU4EOU/D,=LU4ERS/D,=LU4ESP/D,=LU4ETD/D,=LU4ETN/D,=LU4EV/D,=LU4HSA/D,=LU4HTD/D,=LU4MA/D,=LU4UWZ/D, + =LU4UZW/D,=LU4VEN/D,=LU4VSD/D,=LU4WAP/D,=LU5AHN/D,=LU5ALS/D,=LU5AM/D,=LU5ANL/D,=LU5AQV/D, + =LU5ARS/D,=LU5ASA/D,=LU5AVD/D,=LU5BDS/D,=LU5BE/D,=LU5BTL/D,=LU5CBA/D,=LU5CRE/D,=LU5DA/D,=LU5DA/E, + =LU5DAS/D,=LU5DCO/D,=LU5DDH/D,=LU5DEM/D,=LU5DF/D,=LU5DFR/D,=LU5DFT/D,=LU5DGG/D,=LU5DGR/D, + =LU5DHE/D,=LU5DIT/D,=LU5DJE/D,=LU5DKE/D,=LU5DLH/D,=LU5DLT/D,=LU5DLZ/D,=LU5DMI/D,=LU5DMP/D, + =LU5DMR/D,=LU5DQ/D,=LU5DRV/D,=LU5DSH/D,=LU5DSM/D,=LU5DT/D,=LU5DTB/D,=LU5DTF/D,=LU5DUC/D,=LU5DVB/D, + =LU5DWS/D,=LU5DYT/D,=LU5EAO/D,=LU5EC/D,=LU5ED/D,=LU5EDS/D,=LU5EFG/D,=LU5EH/D,=LU5EHC/D,=LU5EJL/D, + =LU5EM/D,=LU5EP/D,=LU5EW/D,=LU5FZ/D,=LU5FZ/E,=LU5JAH/D,=LU5JIB/D,=LU5OD/D,=LU5VAS/D,=LU5VAT/D, + =LU5XP/D,=LU6AER/D,=LU6CN/D,=LU6DAX/D,=LU6DBL/D,=LU6DC/D,=LU6DCT/D,=LU6DDC/D,=LU6DG/D,=LU6DIE/D, + =LU6DIO/D,=LU6DKT/D,=LU6DL/D,=LU6DM/D,=LU6DO/D,=LU6DRD/D,=LU6DRD/E,=LU6DRN/D,=LU6DRR/D,=LU6DSA/D, + =LU6DTB/D,=LU6EAG/D,=LU6EC/D,=LU6EDC/D,=LU6EE/D,=LU6EEG/D,=LU6EGO/D,=LU6EI/D,=LU6EJJ/D,=LU6EKL/D, + =LU6ELP/D,=LU6EMM/D,=LU6ENA/D,=LU6EPE/D,=LU6EPR/D,=LU6EPR/E,=LU6EQV/D,=LU6EU/D,=LU6EVD/D, + =LU6EWR/D,=LU6EXD/D,=LU6HBB/D,=LU6JJ/D,=LU6UAL/D,=LU6UO/D,=LU6UVI/D,=LU6XQ/D,=LU7AA/D,=LU7AC/D, + =LU7ADC/D,=LU7ADN/D,=LU7ART/D,=LU7AVW/D,=LU7BSN/D,=LU7BTO/D,=LU7BTO/E,=LU7CAW/D,=LU7CP/D, + =LU7DAC/D,=LU7DAF/D,=LU7DAR/D,=LU7DBA/D,=LU7DBL/D,=LU7DCE/D,=LU7DD/D,=LU7DDC/D,=LU7DDO/D, + =LU7DHG/D,=LU7DJH/D,=LU7DLN/D,=LU7DNM/D,=LU7DOT/D,=LU7DP/D,=LU7DR/D,=LU7DS/D,=LU7DSC/D,=LU7DSS/D, + =LU7DSU/D,=LU7DSY/D,=LU7DTC/D,=LU7DZL/D,=LU7DZL/E,=LU7DZV/D,=LU7ECZ/D,=LU7EGY/D,=LU7EHL/D, + =LU7EIA/D,=LU7EJC/D,=LU7ELY/D,=LU7EMA/D,=LU7EMM/D,=LU7ENP/D,=LU7EO/D,=LU7EON/D,=LU7EPC/D, + =LU7ETR/D,=LU7HBL/D,=LU7HW/D,=LU7HZ/D,=LU7VCH/D,=LU8ABR/D,=LU8ACH/D,=LU8ADX/D,=LU8AE/D,=LU8ARI/D, + =LU8ATM/D,=LU8DAF/D,=LU8DCF/D,=LU8DCH/D,=LU8DCK/D,=LU8DCM/D,=LU8DIP/D,=LU8DIW/D,=LU8DJR/D, + =LU8DLD/D,=LU8DLT/D,=LU8DMD/D,=LU8DQ/D,=LU8DR/D,=LU8DRA/D,=LU8DRH/D,=LU8DRQ/D,=LU8DSJ/D,=LU8DTF/D, + =LU8DUJ/D,=LU8DVQ/D,=LU8DW/D,=LU8DWR/D,=LU8DX/D,=LU8DY/D,=LU8DZE/D,=LU8DZH/D,=LU8EAG/D,=LU8EAJ/D, + =LU8EBJ/D,=LU8EBJ/E,=LU8EBK/D,=LU8EBK/E,=LU8EC/D,=LU8ECF/D,=LU8ECF/E,=LU8EEM/D,=LU8EFF/D, + =LU8EGC/D,=LU8EGS/D,=LU8EHQ/D,=LU8EHQ/E,=LU8EHS/D,=LU8EHV/D,=LU8EKC/D,=LU8EMC/D,=LU8ERH/D, + =LU8ETC/D,=LU8EU/D,=LU8EXJ/D,=LU8EXN/D,=LU8FAU/D,=LU8VCC/D,=LU8VER/D,=LU9ACJ/D,=LU9AEA/D, + =LU9AOS/D,=LU9AUC/D,=LU9BRC/D,=LU9BSA/D,=LU9CGN/D,=LU9CLH/D,=LU9DA/D,=LU9DAA/D,=LU9DAD/D,=LU9DB/D, + =LU9DE/D,=LU9DEQ/D,=LU9DF/D,=LU9DGE/D,=LU9DKO/D,=LU9DMG/D,=LU9DO/D,=LU9DPD/D,=LU9DPI/D,=LU9DPZ/E, + =LU9DSD/D,=LU9DVO/D,=LU9EAG/D,=LU9ECE/D,=LU9EI/D,=LU9EIM/D,=LU9EJM/D,=LU9EJS/E,=LU9EJZ/D, + =LU9ENH/D,=LU9EOE/D,=LU9ERA/D,=LU9ESD/D,=LU9ESD/E,=LU9ESD/LH,=LU9EV/D,=LU9EV/E,=LU9EV/LH,=LU9EY/D, + =LU9EYE/D,=LU9EZX/D,=LU9HDR/D,=LU9HJV/D,=LU9HVR/D,=LU9USD/D,=LU9WM/D,=LV7E/D,=LW1DAL/D,=LW1DDX/D, + =LW1DE/D,=LW1DEN/D,=LW1DEW/D,=LW1DJ/D,=LW1DOG/D,=LW1DQQ/D,=LW1DVB/D,=LW1DXH/D,=LW1DXP/D,=LW1DYN/D, =LW1DYP/D,=LW1ECE/D,=LW1ECO/D,=LW1ELI/D,=LW1EQI/D,=LW1EQZ/D,=LW1EVO/D,=LW1EXU/D,=LW2DAW/D, =LW2DET/D,=LW2DJM/D,=LW2DNC/D,=LW2DOD/D,=LW2DOM/D,=LW2DSM/D,=LW2DX/E,=LW2DYA/D,=LW2ECK/D, =LW2ECM/D,=LW2EFS/D,=LW2EHD/D,=LW2ENB/D,=LW2EQS/D,=LW2EUA/D,=LW3DAB/D,=LW3DBM/D,=LW3DC/D, =LW3DED/D,=LW3DER/D,=LW3DFP/D,=LW3DG/D,=LW3DGC/D,=LW3DJC/D,=LW3DKC/D,=LW3DKC/E,=LW3DKO/D, - =LW3DKO/E,=LW3DN/D,=LW3DRW/D,=LW3DSR/D,=LW3DTD/D,=LW3EIH/D,=LW3EMP/D,=LW4DAF/D,=LW4DBE/D, + =LW3DKO/E,=LW3DN/D,=LW3DRW/D,=LW3DSR/D,=LW3DTD/D,=LW3EIH/D,=LW3EK/D,=LW3EMP/D,=LW4DAF/D,=LW4DBE/D, =LW4DBM/D,=LW4DCV/D,=LW4DKI/D,=LW4DOR/D,=LW4DRH/D,=LW4DRH/E,=LW4DRV/D,=LW4DTM/D,=LW4DTR/D, =LW4DWV/D,=LW4DXH/D,=LW4ECV/D,=LW4EIN/D,=LW4EM/D,=LW4EM/E,=LW4EM/LH,=LW4ERO/D,=LW4ESY/D,=LW4ETG/D, =LW4EZT/D,=LW4HCL/D,=LW5DAD/D,=LW5DD/D,=LW5DFR/D,=LW5DHG/D,=LW5DIE/D,=LW5DLY/D,=LW5DNN/D, @@ -1809,13 +1846,13 @@ Argentina: 13: 14: SA: -34.80: 65.92: 3.0: LU: =LU1XZ/H,=LU2DVI/H,=LU2HAE/H,=LU2HC/H,=LU2HCG/H,=LU2HEA/H,=LU2HEQ/H,=LU2HJ/H,=LU2HNV/H,=LU2MAA/H, =LU3AJL/H,=LU3FCR/H,=LU3FN/H,=LU3HAT/H,=LU3HAZ/H,=LU3HE/H,=LU3HKA/H,=LU3HL/H,=LU3HPW/H,=LU3HU/H, =LU3HZK/H,=LU4AA/H,=LU4DPL/H,=LU4ETN/H,=LU4FM/H,=LU4HAP/H,=LU4HK/H,=LU4HOQ/H,=LU4HSA/H, - =LU4HSA/LGH,=LU4HTD/H,=LU4MA/H,=LU5DGG/H,=LU5DX/H,=LU5DZ/H,=LU5HA/H,=LU5HAZ/H,=LU5HCB/H,=LU5HCW/H, - =LU5HFW/H,=LU5HGR/H,=LU5HIO/H,=LU5HR/H,=LU5HTA/H,=LU5WTE/H,=LU5YUS/H,=LU6FE/H,=LU6HAS/H,=LU6HBB/H, - =LU6HCA/H,=LU6HGH/H,=LU6HQH/H,=LU6HTR/H,=LU6XQ/H,=LU7ADC/H,=LU7DZ/H,=LU7FBG/H,=LU7FTF/H,=LU7HA/H, - =LU7HBC/H,=LU7HBL/H,=LU7HBV/H,=LU7HCS/H,=LU7HEO/H,=LU7HOM/H,=LU7HOS/H,=LU7HSG/H,=LU7HW/H, - =LU7HWB/H,=LU7HZ/H,=LU8FF/H,=LU8HAR/H,=LU8HBX/H,=LU8HJ/H,=LU8HOR/H,=LU9BSA/H,=LU9DPD/H,=LU9ERA/H, - =LU9HCF/H,=LU9HJV/H,=LU9HVR/H,=LW1HBD/H,=LW1HCM/H,=LW1HDI/H,=LW2EIY/H,=LW3HBS/H,=LW3HOH/H, - =LW4HCL/H,=LW4HTA/H,=LW4HTD/H,=LW6ENV/H,=LW6HAM/H,=LW7EIY/H,=LW7HA/H,=LW9HCF/H, + =LU4HSA/LGH,=LU4HTD/H,=LU4MA/H,=LU5DGG/H,=LU5DX/H,=LU5DZ/H,=LU5FYX/H,=LU5HA/H,=LU5HAZ/H,=LU5HCB/H, + =LU5HCW/H,=LU5HFW/H,=LU5HGR/H,=LU5HIO/H,=LU5HR/H,=LU5HTA/H,=LU5WTE/H,=LU5YUS/H,=LU6FE/H,=LU6HAS/H, + =LU6HBB/H,=LU6HCA/H,=LU6HGH/H,=LU6HQH/H,=LU6HTR/H,=LU6XQ/H,=LU7ADC/H,=LU7DZ/H,=LU7FBG/H,=LU7FTF/H, + =LU7HA/H,=LU7HBC/H,=LU7HBL/H,=LU7HBV/H,=LU7HCS/H,=LU7HEO/H,=LU7HOM/H,=LU7HOS/H,=LU7HSG/H,=LU7HW/H, + =LU7HWB/H,=LU7HZ/H,=LU8FF/H,=LU8HAR/H,=LU8HBX/H,=LU8HH/H,=LU8HJ/H,=LU8HOR/H,=LU9BSA/H,=LU9DPD/H, + =LU9ERA/H,=LU9HCF/H,=LU9HJV/H,=LU9HVR/H,=LW1HBD/H,=LW1HCM/H,=LW1HDI/H,=LW2EIY/H,=LW3HBS/H, + =LW3HOH/H,=LW4HCL/H,=LW4HTA/H,=LW4HTD/H,=LW6ENV/H,=LW6HAM/H,=LW7EIY/H,=LW7HA/H,=LW9HCF/H, =LU1IAL/I,=LU1IBM/I,=LU1IG/I,=LU1II/I,=LU2IP/I,=LU5FZ/I,=LU5IAL/I,=LU5IAO/I,=LU5ILA/I,=LU7IEI/I, =LU7IPI/I,=LU7ITR/I,=LU7IUE/I,=LU8IEZ/I,=LU9IBJ/I, =LU1JAO/J,=LU1JAR/J,=LU1JCE/J,=LU1JCO/J,=LU1JEF/J,=LU1JEO/J,=LU1JES/J,=LU1JHF/J,=LU1JHP/J, @@ -1826,8 +1863,8 @@ Argentina: 13: 14: SA: -34.80: 65.92: 3.0: LU: =LU7JMS/J,=LU7JR/J,=LU7JRM/J,=LU8JOP/J,=LU9JLV/J,=LU9JMG/J,=LU9JPR/J,=LU9YB/J,=LW2DRJ/J,=LW3EMP/J, =LU1KWC/K,=LU2KLC/K,=LU4KC/K,=LU5OM/K,=LU6KAQ/K,=LU7KHB/K,=LU7KT/K,=LU8KE/K,=LW1EVO/K,=LW3DFP/K, =LU1AAS/L,=LU1DZ/L,=LU1LAA/L,=LU1LT/L,=LU1LTL/L,=LU2LDB/L,=LU3AYE/L,=LU4AGC/L,=LU4EFC/L,=LU4LAD/L, - =LU4LBU/L,=LU4LMA/L,=LU5FZ/L,=LU5ILA/L,=LU5LAE/L,=LU5LBV/L,=LU6JRA/L,=LU8IEZ/L,=LU8LFV/L,=LU9JX/L, - =LU9LEW/L,=LU9LZY/L,=LU9LZZ/L,=LU9XPA/L,=LW3EMP/L,=LW8DTO/L, + =LU4LBU/L,=LU4LMA/L,=LU5FZ/L,=LU5ILA/L,=LU5LAE/L,=LU5LBV/L,=LU6JRA/L,=LU8IEZ/L,=LU8LFV/L, + =LU9GOY/L,=LU9JX/L,=LU9LEW/L,=LU9LZY/L,=LU9LZZ/L,=LU9XPA/L,=LW3EMP/L,=LW8DTO/L, =LU3PCJ/MA,=LW4DBE/MA, =LU2DSV/N,=LU3AAL/N,=LU5BE/N,=LU5FZ/N,=LU8EFF/N,=LW5DR/N, =LU1HZY/O,=LU1XS/O,=LU2HON/O,=LU3HL/O,=LU4AA/O,=LU5BOJ/O,=LU5OD/O,=LU6FEC/O,=LU6HWT/O,=LU8OAH/O, @@ -1860,16 +1897,17 @@ Argentina: 13: 14: SA: -34.80: 65.92: 3.0: LU: =LU1VFP/V[16],=LU1VOF/LH[16],=LU1VOF/V[16],=LU1VPH/V[16],=LU1VZ/V[16],=LU1WJV/V[16],=LU1WJY/V[16], =LU1YY/V[16],=LU2DB/V[16],=LU2VA/V[16],=LU2VCD/V[16],=LU2VCR/V[16],=LU2VCS/V[16],=LU2VDV/V[16], =LU2VJU/V[16],=LU2VV/V[16],=LU3AIY/V[16],=LU3DC/V[16],=LU3DR/V[16],=LU3ES/V[16],=LU3VAL/V[16], - =LU3VE/V[16],=LU3VHE/V[16],=LU3VMB/V[16],=LU3VSE/V[16],=LU3VSM/V[16],=LU3XQN/V[16],=LU4AA/V[16], - =LU4DBP/V[16],=LU4DBT/V[16],=LU4DDL/V[16],=LU4EHP/V[16],=LU4EJS/V[16],=LU4VAU/V[16],=LU4VBW/V[16], - =LU4VDG/V[16],=LU4VEN/V[16],=LU4VMB/V[16],=LU4VMG/V[16],=LU4VV/V[16],=LU5AJX/V[16],=LU5BDS/V[16], - =LU5DEM/V[16],=LU5DIT/V[16],=LU5DRV/V[16],=LU5FYX/V[16],=LU5VAI/V[16],=LU5VAS/V[16],=LU5VAT/V[16], - =LU5VFL/V[16],=LU5VIE/V[16],=LU5VLB/V[16],=LU5YBR/V[16],=LU5YF/V[16],=LU6DAI/V[16],=LU6DBL/V[16], - =LU6DKT/V[16],=LU6DO/V[16],=LU6VA/V[16],=LU6VAC/V[16],=LU6VDT/V[16],=LU6VEO/V[16],=LU6VFL/V[16], - =LU6VM/V[16],=LU6VR/V[16],=LU7DSY/V[16],=LU7DW/V[16],=LU7EGH/V[16],=LU7EHL/V[16],=LU7VBT/V[16], - =LU7VFG/V[16],=LU7YZ/V[16],=LU8BV/V[16],=LU8DWR/V[16],=LU8EB/M/V[16],=LU8EHQ/V[16],=LU8VCC/V[16], - =LU8VER/V[16],=LU9AEA/V[16],=LU9DR/V[16],=LU9ESD/V[16],=LU9EY/V[16],=LU9VEA/V[16],=LU9VRC/V[16], - =LUVES/V[16],=LW1ECO/V[16],=LW2DVM/V[16],=LW2DYA/V[16],=LW5EE/V[16],=LW6EQQ/V[16],=LW9EAG/V[16], + =LU3VE/V[16],=LU3VHE/V[16],=LU3VMB/V[16],=LU3VSE/V[16],=LU3VSM/V[16],=LU3XQN/V[16],=LU3YA/V[16], + =LU4AA/V[16],=LU4DBP/V[16],=LU4DBT/V[16],=LU4DDL/V[16],=LU4EHP/V[16],=LU4EJS/V[16],=LU4VAU/V[16], + =LU4VBW/V[16],=LU4VDG/V[16],=LU4VEN/V[16],=LU4VMB/V[16],=LU4VMG/V[16],=LU4VV/V[16],=LU5AJX/V[16], + =LU5BDS/V[16],=LU5DEM/V[16],=LU5DIT/V[16],=LU5DRV/V[16],=LU5FYX/V[16],=LU5VAI/V[16],=LU5VAS/V[16], + =LU5VAT/V[16],=LU5VFL/V[16],=LU5VIE/V[16],=LU5VLB/V[16],=LU5YBR/V[16],=LU5YF/V[16],=LU6DAI/V[16], + =LU6DBL/V[16],=LU6DKT/V[16],=LU6DO/V[16],=LU6VA/V[16],=LU6VAC/V[16],=LU6VDT/V[16],=LU6VEO/V[16], + =LU6VFL/V[16],=LU6VM/V[16],=LU6VR/V[16],=LU7DSY/V[16],=LU7DW/V[16],=LU7EGH/V[16],=LU7EHL/V[16], + =LU7VBT/V[16],=LU7VFG/V[16],=LU7YZ/V[16],=LU8BV/V[16],=LU8DWR/V[16],=LU8EB/M/V[16],=LU8EHQ/V[16], + =LU8VCC/V[16],=LU8VER/V[16],=LU9AEA/V[16],=LU9DR/V[16],=LU9ESD/V[16],=LU9EY/V[16],=LU9VEA/V[16], + =LU9VRC/V[16],=LUVES/V[16],=LW1ECO/V[16],=LW2DVM/V[16],=LW2DYA/V[16],=LW5EE/V[16],=LW6EQQ/V[16], + =LW9EAG/V[16], AY0W[16],AY1W[16],AY2W[16],AY3W[16],AY4W[16],AY5W[16],AY6W[16],AY7W[16],AY8W[16],AY9W[16], AZ0W[16],AZ1W[16],AZ2W[16],AZ3W[16],AZ4W[16],AZ5W[16],AZ6W[16],AZ7W[16],AZ8W[16],AZ9W[16], L20W[16],L21W[16],L22W[16],L23W[16],L24W[16],L25W[16],L26W[16],L27W[16],L28W[16],L29W[16], @@ -1925,12 +1963,12 @@ Argentina: 13: 14: SA: -34.80: 65.92: 3.0: LU: =LU1XP/XP[16],=LU1XPD/XP[16],=LU1XY/X[16],=LU1YY/XA[16],=LU1ZA/XA[16],=LU2CRM/XA[16], =LU2CRM/XB[16],=LU2WA/XA[16],=LU2XBI/XA[16],=LU2XBI/XB[16],=LU2XWL/XP[16],=LU2XX/X[16], =LU2XX/XA[16],=LU2XX/XP[16],=LU3DVN/X[16],=LU3DVN/XP[16],=LU3XEI/X[16],=LU3XEI/XA[16], - =LU3XEM/X[16],=LU3XUC/XP[16],=LU3XUJ/XP[16],=LU3XYL/XP[16],=LU4DBT/XA[16],=LU4XFN/XA[16], - =LU4XPE/XP[16],=LU5BE/XA[16],=LU5BE/XC[16],=LU5DF/X[16],=LU5EMB/X[16],=LU5HJC/X[16], - =LU5HJC/XP[16],=LU5HJK/XP[16],=LU5XC/X[16],=LU5XP/X[16],=LU5XWA/XP[16],=LU6EE/XA[16], - =LU6XAH/X[16],=LU7DSY/XA[16],=LU7EUI/XP[16],=LU7XDY/X[16],=LU7XDY/XA[16],=LU7XSC/XP[16], - =LU8DLD/XA[16],=LU8DRA/XA[16],=LU8EOT/X[16],=LU8XC/X[16],=LU8XUU/XP[16],=LU8XW/X[16], - =LU8XW/XP[16],=LU9DPD/XA[16],=LU9HUP/X[16],=LW3DKO/XA[16],=LW3ET/XP[16], + =LU3XEM/X[16],=LU3XUC/XP[16],=LU3XUJ/XP[16],=LU3XYL/XP[16],=LU4DBT/XA[16],=LU4XAP/XA[16], + =LU4XFN/XA[16],=LU4XPE/XP[16],=LU5BE/XA[16],=LU5BE/XC[16],=LU5DF/X[16],=LU5EMB/X[16], + =LU5HJC/X[16],=LU5HJC/XP[16],=LU5HJK/XP[16],=LU5XC/X[16],=LU5XP/X[16],=LU5XWA/XP[16], + =LU6EE/XA[16],=LU6XAH/X[16],=LU7DSY/XA[16],=LU7EUI/XP[16],=LU7XDY/X[16],=LU7XDY/XA[16], + =LU7XSC/XP[16],=LU8DLD/XA[16],=LU8DRA/XA[16],=LU8EOT/X[16],=LU8XC/X[16],=LU8XUU/XP[16], + =LU8XW/X[16],=LU8XW/XP[16],=LU9DPD/XA[16],=LU9HUP/X[16],=LW3DKO/XA[16],=LW3ET/XP[16], AY0Y[16],AY1Y[16],AY2Y[16],AY3Y[16],AY4Y[16],AY5Y[16],AY6Y[16],AY7Y[16],AY8Y[16],AY9Y[16], AZ0Y[16],AZ1Y[16],AZ2Y[16],AZ3Y[16],AZ4Y[16],AZ5Y[16],AZ6Y[16],AZ7Y[16],AZ8Y[16],AZ9Y[16], L20Y[16],L21Y[16],L22Y[16],L23Y[16],L24Y[16],L25Y[16],L26Y[16],L27Y[16],L28Y[16],L29Y[16], @@ -1951,12 +1989,12 @@ Argentina: 13: 14: SA: -34.80: 65.92: 3.0: LU: LV0Y[16],LV1Y[16],LV2Y[16],LV3Y[16],LV4Y[16],LV5Y[16],LV6Y[16],LV7Y[16],LV8Y[16],LV9Y[16], LW0Y[16],LW1Y[16],LW2Y[16],LW3Y[16],LW4Y[16],LW5Y[16],LW6Y[16],LW7Y[16],LW8Y[16],LW9Y[16], =LU1DZ/Y[16],=LU1YDC/Y[16],=LU1YY/Y[16],=LU2VA/Y[16],=LU2VDQ/Y[16],=LU2XAN/Y[16],=LU2YMG/Y[16], - =LU3XAP/XA[16],=LU3YEP/Y[16],=LU4AA/Y[16],=LU4DRC/Y[16],=LU4XAP/XA[16],=LU4XEG/XA[16], - =LU4YAB/Y[16],=LU4YAD/Y[16],=LU4YAL/Y[16],=LU5HLR/Y[16],=LU5YF/Y[16],=LU6VEO/Y[16],=LU6VM/Y[16], - =LU6YAB/Y[16],=LU6YBK/Y[16],=LU6YSG/Y[16],=LU7XBX/XA[16],=LU7YCL/Y[16],=LU7YG/Y[16],=LU7YP/Y[16], - =LU8DQ/Y[16],=LU8DRA/Y[16],=LU8EOT/Y[16],=LU8IEZ/Y[16],=LU8VCC/Y[16],=LU8XBC/XA[16], - =LU8XBS/XA[16],=LU8YAH/Y[16],=LU8YD/Y[16],=LU8YE/Y[16],=LU8YMP/Y[16],=LU8YSF/Y[16],=LU9BSA/Y[16], - =LU9ESD/Y[16],=LU9XCC/XA[16],=LW1EXU/Y[16],=LW2DX/Y[16],=LW7DLY/Y[16],=LW7DQQ/Y[16],=LW9DCF/Y[16]; + =LU3XAP/XA[16],=LU3YEP/Y[16],=LU4AA/Y[16],=LU4DRC/Y[16],=LU4XEG/XA[16],=LU4YAB/Y[16], + =LU4YAD/Y[16],=LU4YAL/Y[16],=LU5HLR/Y[16],=LU5YF/Y[16],=LU6VEO/Y[16],=LU6VM/Y[16],=LU6YAB/Y[16], + =LU6YBK/Y[16],=LU6YSG/Y[16],=LU7XBX/XA[16],=LU7YCL/Y[16],=LU7YG/Y[16],=LU7YP/Y[16],=LU8DQ/Y[16], + =LU8DRA/Y[16],=LU8EOT/Y[16],=LU8IEZ/Y[16],=LU8VCC/Y[16],=LU8XBC/XA[16],=LU8XBS/XA[16], + =LU8YAH/Y[16],=LU8YD/Y[16],=LU8YE/Y[16],=LU8YMP/Y[16],=LU8YSF/Y[16],=LU9BSA/Y[16],=LU9ESD/Y[16], + =LU9XCC/XA[16],=LW1EXU/Y[16],=LW2DX/Y[16],=LW7DLY/Y[16],=LW7DQQ/Y[16],=LW9DCF/Y[16]; Luxembourg: 14: 27: EU: 50.00: -6.00: -1.0: LX: LX,=LX9S/J; Lithuania: 15: 29: EU: 55.45: -23.63: -2.0: LY: @@ -1970,8 +2008,8 @@ Peru: 10: 12: SA: -10.00: 76.00: 5.0: OA: Lebanon: 20: 39: AS: 33.83: -35.83: -2.0: OD: OD,=OD5NJ/ID,=OD5QB/ID,=OD5RI/YOTA; Austria: 15: 28: EU: 47.33: -13.33: -1.0: OE: - OE,=4U0R,=4U10NPT,=4U18FIFA,=4U1A,=4U1VIC,=4U1WED,=4U1XMAS,=4U2U,=4U30VIC,=4U70VIC,=4Y1A,=C7A, - =OE2015XHQ/SC,=OE6XMF/U20, + OE,=4U0R,=4U10NPT,=4U18FIFA,=4U1A,=4U1VIC,=4U1WED,=4U1XMAS,=4U2U,=4U30VIC,=4U500M,=4U70VIC,=4Y1A, + =C7A,=OE2015XHQ/SC,=OE6XMF/U20, =OE3AIS/ANT, =OE3AGA/AAW,=OE3AIS/AAW,=OE3HM/AAW,=OE3KKA/AAW,=OE3KKA/ANT,=OE3KTA/ANT,=OE3MWS/Y2K,=OE3RPB/AAW, =OE3RPB/ANT,=OE3SGA/AAW,=OE3SGA/ANT,=OE3WWB/AAW,=OE3WWB/ANT,=OE4VIE/ANT, @@ -2049,18 +2087,19 @@ Netherlands: 14: 27: EU: 52.28: -5.47: -1.0: PA: =PA3CPI/JOTA,=PA3DEW/J,=PA3EEQ/LH,=PA3EFR/J,=PA3ESO/J,=PA3EWG/J,=PA3FBO/LH,=PA3FYE/J,=PA3GAG/LH, =PA3GQS/J,=PA3GWN/J,=PA3HFJ/J,=PA3WSK/JOTA,=PA40LAB/J,=PA4RVS/MILL,=PA4WK/J,=PA5CA/LH,=PA65DUIN/J, =PA65URK/LH,=PA6ADZ/MILL,=PA6ARC/LH,=PA6FUN/LGT,=PA6FUN/LH,=PA6FUN/LS,=PA6HOOP/MILL,=PA6HYG/J, - =PA6JAM/J,=PA6KMS/MILL,=PA6LH/LH,=PA6LL/LH,=PA6LST/LH,=PA6LST/LS,=PA6MZD/MILL,=PA6RCG/J,=PA6SB/L, - =PA6SB/LH,=PA6SCH/LH,=PA6SHB/J,=PA6SJB/J,=PA6SJS/J,=PA6STAR/MILL,=PA6URK/LH,=PA6VEN/LH,=PA6VLD/LH, - =PA6WAD/LGT,=PA70HYG/JOTA,=PA75SM/J,=PA7AL/LH,=PA7HPH/J,=PA7JWC/J,=PA99HYG/JOTA,=PA9M/LH,=PB6F/LH, - =PB6KW/LH,=PB88XYL/YL,=PB9ZR/J,=PC2D/LH,=PD0ARI/MILL,=PD0FSB/LH,=PD1JL/MILL,=PD1JSH/J,=PD2C/LH, - =PD2GCM/LH,=PD5CW/LH,=PD5MVH/P/LH,=PD7DX/J,=PE18KA/J,=PE1NCS/LGT,=PE1NCS/LH,=PE1NZJ/J,=PE1OPM/LH, - =PE1OXI/J,=PE1RBG/J,=PE1RBR/J,=PE2MC/J,=PE2MGA/J,=PF100ROVER/J,=PF18NAWAKA/J,=PF4R/LH,=PG150N/LH, - =PG6HK/LH,=PG6N/LH,=PH4RTM/MILL,=PH4RTM/WHE,=PH50GFB/J,=PH6BB/J,=PH6WAL/LH,=PH75S/J,=PH9GFB/J, - =PI4ADH/LGT,=PI4ADH/LH,=PI4ADH/LS,=PI4ALK/LH,=PI4AZL/J,=PI4BG/J,=PI4BOZ/LH,=PI4CQ/J,=PI4DHG/DM, - =PI4DHG/MILL,=PI4ET/MILL,=PI4ETL/MILL,=PI4F/LH,=PI4LDN/L,=PI4LDN/LH,=PI4RCK/LGT,=PI4RCK/LH, - =PI4RIS/J,=PI4S/J,=PI4SHV/J,=PI4SRN/LH,=PI4SRN/MILL,=PI4VNW/LGT,=PI4VNW/LH,=PI4VPO/LH,=PI4VPO/LT, - =PI4WAL/LGT,=PI4WAL/LH,=PI4WBR/LH,=PI4WFL/MILL,=PI4YLC/LH,=PI4ZHE/LH,=PI4ZHE/LS,=PI4ZHE/MILL, - =PI4ZVL/FD,=PI4ZVL/LGT,=PI4ZVL/LH,=PI9NHL/LH,=PI9SRS/LH,=PI9TP/J; + =PA6JAM/J,=PA6KMS/MILL,=PA6LH/LH,=PA6LL/LH,=PA6LST/LH,=PA6LST/LS,=PA6MZD/MILL,=PA6OP/MILL, + =PA6RCG/J,=PA6SB/L,=PA6SB/LH,=PA6SCH/LH,=PA6SHB/J,=PA6SJB/J,=PA6SJS/J,=PA6STAR/MILL,=PA6URK/LH, + =PA6VEN/LH,=PA6VLD/LH,=PA6WAD/LGT,=PA70HYG/JOTA,=PA75SM/J,=PA7AL/LH,=PA7HPH/J,=PA7JWC/J, + =PA99HYG/JOTA,=PA9M/LH,=PB6F/LH,=PB6KW/LH,=PB88XYL/YL,=PB9ZR/J,=PC2D/LH,=PD0ARI/MILL,=PD0FSB/LH, + =PD1JL/MILL,=PD1JSH/J,=PD2C/LH,=PD2GCM/LH,=PD5CW/LH,=PD5MVH/P/LH,=PD7DX/J,=PE18KA/J,=PE1NCS/LGT, + =PE1NCS/LH,=PE1NZJ/J,=PE1OPM/LH,=PE1OXI/J,=PE1RBG/J,=PE1RBR/J,=PE2MC/J,=PE2MGA/J,=PF100ROVER/J, + =PF18NAWAKA/J,=PF4R/LH,=PG150N/LH,=PG64HOOP/MIL,=PG6HK/LH,=PG6N/LH,=PH4RTM/MILL,=PH4RTM/WHE, + =PH50GFB/J,=PH6BB/J,=PH6WAL/LH,=PH75S/J,=PH9GFB/J,=PI4ADH/LGT,=PI4ADH/LH,=PI4ADH/LS,=PI4ALK/LH, + =PI4AZL/J,=PI4BG/J,=PI4BOZ/LH,=PI4CQ/J,=PI4DHG/DM,=PI4DHG/MILL,=PI4ET/MILL,=PI4ETL/MILL,=PI4F/LH, + =PI4LDN/L,=PI4LDN/LH,=PI4RCK/LGT,=PI4RCK/LH,=PI4RIS/J,=PI4S/J,=PI4SHV/J,=PI4SRN/LH,=PI4SRN/MILL, + =PI4VNW/LGT,=PI4VNW/LH,=PI4VPO/LH,=PI4VPO/LT,=PI4WAL/LGT,=PI4WAL/LH,=PI4WBR/LH,=PI4WFL/MILL, + =PI4YLC/LH,=PI4ZHE/LH,=PI4ZHE/LS,=PI4ZHE/MILL,=PI4ZVL/FD,=PI4ZVL/LGT,=PI4ZVL/LH,=PI4ZWN/MILL, + =PI9NHL/LH,=PI9SRS/LH,=PI9TP/J; Curacao: 09: 11: SA: 12.17: 69.00: 4.0: PJ2: PJ2; Bonaire: 09: 11: SA: 12.20: 68.25: 4.0: PJ4: @@ -2088,10 +2127,10 @@ Brazil: 11: 15: SA: -10.00: 53.00: 3.0: PY: =PT9AA/SD, PV8[12],=PV8DX/SD[12],=PV8IG/SD[12], PW8[12],=PW8AA/SD[12], - =PY1AA/LH,=PY1AA/SD,=PY1CML/SD,=PY1DCS/SD,=PY1DCX/SD,=PY1WC/SD, + =PY1AA/LH,=PY1AA/SD,=PY1CML/SD,=PY1CRN/LH,=PY1DCS/SD,=PY1DCX/SD,=PY1WC/SD, =PU2AIL/YL,=PY2ASS/C,=PY2DS/Q,=PY2NDX/SD,=PY2TDP/SD,=ZX2T/SD,=ZY2CPC/SD, =PU3KIT/YL,=PY3AA/LH,=PY3AA/SD,=PY3COM/SD,=PY3CQ/LH,=PY3CRA/SD,=PY3MHZ/SD,=PY3MSS/YL,=PY3RCA/SD, - =PY3RT/SD,=PY3UGR/SD,=PY3UR/SD,=PY3UU/SD, + =PY3RT/SD,=PY3UGR/SD,=PY3UR/SD,=PY3UU/SD,=ZW3RS/LH, =PY4CEL/SD,=PY4CLK/SD,=PY4MAB/BNC,=PY4VL/SD,=PY4XX/SD,=ZW4CPC/SD, =PY5AA/SD, PY6[13],=ZY6BI/SD[13],=ZY6MP/SD[13], @@ -2156,14 +2195,15 @@ Greece: 20: 28: EU: 39.78: -21.78: -2.0: SV: J4,SV,SW,SX,SY,SZ,=J42004/DH1NA,=J42004/DH1PS,=J42004/HA3NU,=J42004/N3JWJ,=J42004/OE5ER,=SV54FF, =SX90IARU, =SV1/LY1DF/LGT,=SV1EOS/JOTA,=SV1EQU/J,=SV5FRI/1,=SV5FRQ/1,=SV9AWF/1,=SV9CUF/1,=SV9DRU/1,=SV9TJ/1, - =SV2CLJ/J,=SV2JAO/J,=SV2KBB/J,=SV2RNY/J,=SX100TSL/J,=SY2AEI/J,=SY2WT/LH,=SZ2TSL/J, + =SV2CLJ/J,=SV2JAO/J,=SV2KBB/J,=SV2RNY/J,=SV94MIKIS,=SV94THEO,=SX100TSL/J,=SX94MIKIS,=SX94THEO, + =SY2AEI/J,=SY2WT/LH,=SZ2TSL/J, =SV5CJK/3,=SV5FRK/3,=SV5FRP/3,=SV9ION/3, =SV9OFL/4, =SV9DJO/7,=SZ7KAM/LH, =SV5KJQ/8,=SV8/DJ5AA/LH,=SV8/LY1DF/LGT,=SV9GPM/8,=SW8SW/LH,=SX8DI/LH,=SZ8LES/LH,=SZ8XIO/J, =SZ8XIO/P/JOTA; Mount Athos: 20: 28: EU: 40.00: -24.00: -2.0: SV/a: - =SV2/SV1RP/T,=SV2ASP/A,=SV2RSG/A,=SY2A; + =SV2/SV1RP/T,=SV2ASP,=SV2ASP/A,=SV2ASP/P,=SV2RSG/A,=SY2A; Dodecanese: 20: 28: EU: 36.17: -27.93: -2.0: SV5: J45,SV5,SW5,SX5,SY5,SZ5,=J42004/SP5MXZ,=J45FRE/J,=SV0XAN/5,=SV0XBZ/5,=SV0XCA/5,=SV0XCA/P, =SV1ENJ/5,=SV1GSX/5,=SV5/DJ5AA/LH,=SV5/LY1DF/LGT,=SV5CJQ/LH,=SV9DJO/5,=SV9GPV/5,=SV9JI/5, @@ -2232,34 +2272,34 @@ Benin: 35: 46: AF: 9.87: -2.25: -1.0: TY: Mali: 35: 46: AF: 18.00: 2.58: 0.0: TZ: TZ; European Russia: 16: 29: EU: 53.65: -41.37: -4.0: UA: - R,U,=R0CAF/1,=R25EMW(17)[19],=R7AB/M,=R7AB/P,=R80PSP,=R80UPOL,=R8CT/4/P,=R8FF/3/M,=R90DOSAAF, + R,U,=R0AGD/6,=R0CAF/1,=R25EMW(17)[19],=R7AB/M,=R80PSP,=R80UPOL,=R8CT/4/P,=R8FF/3/M,=R90DOSAAF, =R9AV/6,=R9FAZ/6/M,=R9FCH/6,=R9JI/1,=R9KC/6/M,=R9WR/1,=R9XAU/6,=RA0AM/6,=RA0BM/6,=RA0ZZ/3, - =RA2FDX/3,=RA3CQ/9/M(17)[20],=RA80SP,=RA9JR/3,=RA9JX/3,=RA9P/4,=RA9RT/3,=RA9YA/6,=RC80SP,=RG0F/5, + =RA3CQ/9/M(17)[20],=RA80SP,=RA9JR/3,=RA9JX/3,=RA9P/4,=RA9RT/3,=RA9UUY/6,=RA9YA/6,=RC80SP,=RG0F/5, =RG50P(17),=RG50P/9(17)[30],=RJ80SP,=RK80X(17)[19],=RK8O/4,=RL9AA/6,=RM80SP,=RM8A/4/M,=RM94AE, =RN9M/4,=RN9OI/3,=RO80RO,=RP61XX(17)[19],=RP62X(17)[19],=RP63X(17)[19],=RP63XO(17)[19], =RP64X(17)[19],=RP65FPP(17)[30],=RP8X(17)[30],=RQ80SP,=RU0ZW/6,=RU2FB/3,=RU2FB/3/P, =RU4SS/9(17)[30],=RU4WA/9(17)[30],=RV9LM/3,=RV9XX/3,=RW0IM/1,=RW0QE/6,=RW2F/6,=RW9FF/3,=RW9W/3, =RW9W/4,=RX2FS/3,=RX9TC/1,=RX9UL/1,=RZ9AWN/6,=UA0AK/3,=UA0FQ/6,=UA0KBG/3,=UA0KBG/6,=UA0KCX/3/P, =UA0KT/4,=UA0QNE/3,=UA0QNU/3,=UA0QQJ/3,=UA0UV/6,=UA0XAK/3,=UA0XAK/6,=UA0ZL/6,=UA9CCO/6,=UA9CTT/3, - =UA9CTT/6,=UA9FFS/1/MM,=UE23DKA,=UE23DSA,=UE6MAC/9(17),=UE95AE,=UE95E,=UE95ME,=UE96ME,=UE99PS, - =R900BL,=R9J/1,=RA2FN/1,=RA9KU/1,=RA9KU/1/M,=RA9MC/1,=RA9SGI/1,=RK9XWV/1,=RL1O,=RM80DZ,=RN85AM, - =RN85KN,=RT9T/1,=RU2FB/1,=RU9YT/1,=RU9YT/1/P,=RV1CC/M,=RW1AI/ANT,=RW8W/1,=RW9QA/1,=RX3AMI/1/LH, - =UA1ADQ/ANT,=UA1BJ/ANT,=UA1JJ/ANT,=UA2FFX/1,=UA9B/1,=UA9KG/1,=UA9KGH/1,=UA9KK/1,=UA9UDX/1, - =UB9YUW/1,=UE21A,=UE21B,=UE21M,=UE22A,=UE25AC,=UE25AQ,=UE2AT/1, - =R0XAC/1,=R900DM,=R90LPU,=R9JNO/1,=RA0FU/1,=RA9FNV/1,=RU9MU/1,=RV0CA/1,=RV2FW/1,=RV9JD/1,=RX9TN/1, - =UA0BDS/1,=UA0SIK/1,=UA1CDA/LH,=UA1CIO/LH,=UA9MQR/1,=UB5O/1, + =UA9CTT/6,=UA9FFS/1/MM,=UE23DKA,=UE6MAC/9(17),=UE95AE,=UE95E,=UE95ME,=UE96ME,=UE99PS, + =R900BL,=R9J/1,=RA2FN/1,=RA9KU/1,=RA9KU/1/M,=RA9MC/1,=RA9SGI/1,=RK9XWV/1,=RL1O,=RM0L/1,=RM80DZ, + =RN85AM,=RN85KN,=RT9T/1,=RU2FB/1,=RU9YT/1,=RU9YT/1/P,=RW1AI/ANT,=RW8W/1,=RW9QA/1,=UA1ADQ/ANT, + =UA1BJ/ANT,=UA1JJ/ANT,=UA2FFX/1,=UA9B/1,=UA9KG/1,=UA9KGH/1,=UA9KK/1,=UA9UDX/1,=UB9YUW/1,=UE21A, + =UE21B,=UE21M,=UE22A,=UE25AC,=UE25AQ,=UE2AT/1, + =R0XAC/1,=R8XF/1,=R900DM,=R90LPU,=R9JNO/1,=RA0FU/1,=RA9FNV/1,=RN9N/1,=RU9MU/1,=RV0CA/1,=RV1CC/M, + =RV2FW/1,=RV9JD/1,=RX9TN/1,=UA0BDS/1,=UA0SIK/1,=UA1CDA/LH,=UA1CIO/LH,=UA9MQR/1,=UB5O/1, R1N[19],RA1N[19],RC1N[19],RD1N[19],RE1N[19],RF1N[19],RG1N[19],RJ1N[19],RK1N[19],RL1N[19],RM1N[19], RN1N[19],RO1N[19],RQ1N[19],RT1N[19],RU1N[19],RV1N[19],RW1N[19],RX1N[19],RY1N[19],RZ1N[19],U1N[19], UA1N[19],UB1N[19],UC1N[19],UD1N[19],UE1N[19],UF1N[19],UG1N[19],UH1N[19],UI1N[19],=R01DTV/1[19], - =R85KFF[19],=R90K[19],=RN1NA/ANT[19],=RO25KL[19],=RP72PT[19],=RP72RK[19],=RP73PT[19],=RP73RK[19], - =RV1CC/1[19],=RV9JD/1/M[19], + =R85KFF[19],=R90K[19],=RK75OP[19],=RN1NA/ANT[19],=RO25KL[19],=RP72PT[19],=RP72RK[19],=RP73PT[19], + =RP73RK[19],=RP74PT[19],=RP74RK[19],=RV9JD/1/M[19],=RX3AMI/1/LH[19], R1O[19],RA1O[19],RC1O[19],RD1O[19],RE1O[19],RF1O[19],RG1O[19],RJ1O[19],RK1O[19],RL1O[19],RM1O[19], RN1O[19],RO1O[19],RQ1O[19],RT1O[19],RU1O[19],RV1O[19],RW1O[19],RX1O[19],RY1O[19],RZ1O[19],U1O[19], UA1O[19],UB1O[19],UC1O[19],UD1O[19],UE1O[19],UF1O[19],UG1O[19],UH1O[19],UI1O[19],=R0000O[19], =R100K[19],=R20ARRS[19],=R25ILIM[19],=R8FF/1[19],=R9LI/1[19],=R9MCM/1[19],=RA0NN/1[19], =RA9XA/1[19],=RA9XA/1/P[19],=RK0SE/1[19],=RM9X/1[19],=RO80KEDR[19],=RP72A[19],=RP73A[19], - =RP73AU[19],=UA1PAC/ANT[19],=UA9UAX/1[19],=UA9UAX/1/M[19],=UA9XK/1[19],=UA9XMC/1[19], - =UA9XRK/1[19],=UE25IK[19],=UE80AR[19],=UE80AR/M[19],=UE80AR/P[19], + =RP73AU[19],=RP74A[19],=RP74AU[19],=UA1PAC/ANT[19],=UA9UAX/1[19],=UA9UAX/1/M[19],=UA9XK/1[19], + =UA9XMC/1[19],=UA9XRK/1[19],=UE25IK[19],=UE80AR[19],=UE80AR/M[19],=UE80AR/P[19], R1P[20],RA1P[20],RC1P[20],RD1P[20],RE1P[20],RF1P[20],RG1P[20],RJ1P[20],RK1P[20],RL1P[20],RM1P[20], RN1P[20],RO1P[20],RQ1P[20],RT1P[20],RU1P[20],RV1P[20],RW1P[20],RX1P[20],RY1P[20],RZ1P[20],U1P[20], UA1P[20],UB1P[20],UC1P[20],UD1P[20],UE1P[20],UF1P[20],UG1P[20],UH1P[20],UI1P[20],=R8XW/1[20], @@ -2267,20 +2307,20 @@ European Russia: 16: 29: EU: 53.65: -41.37: -4.0: UA: =RK1PWA/ANT[20],=RL1P[20],=RN2FA/1[20],=UA1PAC/1/ANT[20],=UA9FOJ/1[20],=UA9MRY/1[20], =UA9XRP/1[20], =R9FM/1,=RA0BM/1,=RA0BM/1/P,=RA1QQ/LH,=RU9MX/1,=RW9XC/1,=UA1QV/ANT,=UA9XC/1,=UE80GS, - =R88EPC,=R95NRL,=RA9FBV/1,=RA9SC/1,=RA9XY/1,=RV2FW/1/M,=RZ0IWW/1,=UA9XF/1,=UE9WFF/1, + =R88EPC,=R95NRL,=RA9FBV/1,=RA9SC/1,=RA9XY/1,=RV1CC/1,=RV2FW/1/M,=RZ0IWW/1,=UA9XF/1,=UE9WFF/1, =RA0ZD/1,=RP9X/1,=RP9XWM/1,=UE25WDW,=UE9XBW/1,=UF2F/1/M, R1Z[19],RA1Z[19],RC1Z[19],RD1Z[19],RE1Z[19],RF1Z[19],RG1Z[19],RJ1Z[19],RK1Z[19],RL1Z[19],RM1Z[19], RN1Z[19],RO1Z[19],RQ1Z[19],RT1Z[19],RU1Z[19],RV1Z[19],RW1Z[19],RX1Z[19],RY1Z[19],RZ1Z[19],U1Z[19], UA1Z[19],UB1Z[19],UC1Z[19],UD1Z[19],UE1Z[19],UF1Z[19],UG1Z[19],UH1Z[19],UI1Z[19],=R25RRA[19], =RA9CFH/1[19],=RA9CFH/1/P[19],=RK21Z[19],=RK3DZJ/1/LH[19],=RM9WN/1[19],=RP72MU[19],=RP73MU[19], - =RP73ZP[19],=RU1ZC/ANT[19],=RW1ZQ/LH[19],=RY83HN[19],=UB1ZBD/N[19], - =R01DTV/3,=R85PAR,=R870B,=R870C,=R870K,=R870M,=R870O,=R9FM/3,=RA2AT,=RA9CO/3,=RA9USU/3,=RC85MP, - =RL3AB/FF,=RT2F/3/M,=RT9K/3,=RW0LF/3,=RX9UL/3,=RX9WN/3,=RZ9UA/3,=UA0KCX/3,=UA3AV/ANT,=UA8AA/3, - =UA8AA/5,=UA9KHD/3,=UA9MDU/3,=UA9MRX/3,=UA9QCP/3,=UA9UAX/3,=UE24SU, - =R85QMR,=R85WDW,=R8B,=R8FF/3,=R90DNF,=R99FSB,=RA0BY/3,=RA80KEDR,=RA9KV/3,=RA9SB/3,=RA9XY/3, - =RK3DSW/ANT,=RK3DWA/3/N,=RN9MD/3,=RT80KEDR,=RU0LM/3,=RU2FA/3,=RU3HD/ANT,=RV0AO/3,=RV9LM/3/P, - =RW0IM/3,=RW3DU/N,=RW9UEW/3,=RX9SN/3,=RZ9SZ/3,=RZ9W/3,=UA0JAD/3,=UA0KCL/3,=UA0ZAZ/3,=UA9AJ/3/M, - =UA9DD/3,=UA9HSI/3,=UA9ONJ/3,=UA9XGD/3,=UA9XMC/3,=UE25FO,=UE95GA,=UE96WS, + =RP73ZP[19],=RP74ZP[19],=RU1ZC/ANT[19],=RW1ZQ/LH[19],=RY83HN[19],=UB1ZBD/N[19], + =R01DTV/3,=R85PAR,=R870B,=R870C,=R870K,=R870M,=R870O,=R9FM/3,=RA2AT,=RA2FDX/3,=RA9CO/3,=RA9USU/3, + =RC85MP,=RL3AB/FF,=RT2F/3/M,=RT9K/3,=RW0LF/3,=RX9UL/3,=RX9WN/3,=RZ9UA/3,=UA0KCX/3,=UA3AV/ANT, + =UA8AA/3,=UA8AA/5,=UA9KHD/3,=UA9MDU/3,=UA9MRX/3,=UA9QCP/3,=UA9UAX/3,=UE24SU, + =R85AAL,=R85QMR,=R85WDW,=R8B,=R8FF/3,=R90DNF,=R99FSB,=RA0BY/3,=RA80KEDR,=RA9KV/3,=RA9SB/3, + =RA9XY/3,=RK3DSW/ANT,=RK3DWA/3/N,=RN9MD/3,=RT80KEDR,=RU0LM/3,=RU2FA/3,=RU3HD/ANT,=RV0AO/3, + =RV9LM/3/P,=RW0IM/3,=RW3DU/N,=RW9UEW/3,=RX9SN/3,=RZ9SZ/3,=RZ9W/3,=UA0JAD/3,=UA0KCL/3,=UA0ZAZ/3, + =UA9AJ/3/M,=UA9DD/3,=UA9HSI/3,=UA9ONJ/3,=UA9XGD/3,=UA9XMC/3,=UE23DSA,=UE25FO,=UE95GA,=UE96WS, =R80ORL,=UA0QGM/3,=UE80O,=UE80OL, =R0CAF/3,=R3GO/FF,=RM0L/3,=RN3GL/FF,=RN3GW/FF,=RT5G/P/FF,=RW0IW/3,=UA3GM/ANT,=UE90FL, =RA9KT/3,=RZ9SZ/3/M,=UA0FHC/3,=UF2F/3/M, @@ -2308,7 +2348,7 @@ European Russia: 16: 29: EU: 53.65: -41.37: -4.0: UA: =UE00S,=UE00S/P,=UE09VG,=UE80RWW, =R4CDX/FF,=R8FF/4,=R8FR/4/M,=RA9KO/4,=RL96WS,=RL97WS,=RU80KEDR,=RU80KEDR/P,=RU9SO/4/M,=RV4CC/FF, =RV9CX/4/M,=RW0UZ/4,=RW9AW/4/M,=RZ0SB/4,=UA0KAT/4,=UA8WAA/4,=UA9AGR/4/M,=UA9JPX/4,=UA9OC/4, - =UE95MS,=UE95WS,=UE98WS,=UE99PW, + =UE23DZO,=UE95MS,=UE95WS,=UE98WS,=UE99PW, =R9CMA/4,=R9JBN/4, R4H[30],R4I[30],RA4H[30],RA4I[30],RC4H[30],RC4I[30],RD4H[30],RD4I[30],RE4H[30],RE4I[30],RF4H[30], RF4I[30],RG4H[30],RG4I[30],RJ4H[30],RJ4I[30],RK4H[30],RK4I[30],RL4H[30],RL4I[30],RM4H[30], @@ -2316,16 +2356,17 @@ European Russia: 16: 29: EU: 53.65: -41.37: -4.0: UA: RU4I[30],RV4H[30],RV4I[30],RW4H[30],RW4I[30],RX4H[30],RX4I[30],RY4H[30],RY4I[30],RZ4H[30], RZ4I[30],U4H[30],U4I[30],UA4H[30],UA4I[30],UB4H[30],UB4I[30],UC4H[30],UC4I[30],UD4H[30],UD4I[30], UE4H[30],UE4I[30],UF4H[30],UF4I[30],UG4H[30],UG4I[30],UH4H[30],UH4I[30],UI4H[30],UI4I[30], - =R20SAM[30],=R280TLT[30],=R4HAT[29],=R4HC[29],=R4HCE[29],=R4HCZ[29],=R4HD[29],=R4HDC[29], - =R4HDR[29],=R4HL[29],=R4IC[29],=R4ID[29],=R4II[29],=R4IK[29],=R4IM[29],=R4IN[29],=R4IO[29], - =R4IT[29],=R9DA/4[30],=RA4HL[29],=RA9FAA/4/M[30],=RA9SC/4[30],=RA9SC/4/P[30],=RC18SA[30], - =RC20HZ[30],=RC4HT[29],=RC4I[29],=RC9YA/4/M[30],=RJ4I[29],=RK4HM[29],=RM4I[29],=RN4HFJ[29], - =RN4HIF[29],=RN9S/M[30],=RP72AG[30],=RP72I[30],=RP72MF[30],=RP72WO[30],=RP73DD[30],=RP73I[30], - =RP73PM[30],=RT9K/4[30],=RU4HD[29],=RU4HP[29],=RU4I[29],=RU9CK/4/M[30],=RV9JD/4/M[30],=RW4HM[29], - =RW4HTK[29],=RW4HW[29],=RW4HZ[29],=RW9SW/4[30],=RW9TP/4[30],=RW9WJ/4[30],=RW9WJ/4/P[30], - =RW9WJ/P[30],=RZ4HWF/LH[30],=RZ4HZW/FF[30],=RZ9WU/4/M[30],=UA0KAO/4[30],=UA0QJA/4[30],=UA4H[29], - =UA4HBM[29],=UA4HGL[29],=UA4HIP[29],=UA4HIP/M[30],=UA4HRZ[29],=UA4HY[29],=UA9JGX/4[30], - =UA9LAO/4[30],=UA9SQG/4/P[30],=UA9SY/4[30],=UC4I[29],=UI4I[29], + =R20SAM[30],=R280TLT[30],=R3ARS/4[30],=R4HAT[29],=R4HC[29],=R4HCE[29],=R4HCZ[29],=R4HD[29], + =R4HDC[29],=R4HDR[29],=R4HL[29],=R4IC[29],=R4ID[29],=R4II[29],=R4IK[29],=R4IM[29],=R4IN[29], + =R4IO[29],=R4IT[29],=R9DA/4[30],=RA4HL[29],=RA9FAA/4/M[30],=RA9SC/4[30],=RA9SC/4/P[30], + =RC18SA[30],=RC20HZ[30],=RC4HT[29],=RC4I[29],=RC9YA/4/M[30],=RJ4I[29],=RK4HM[29],=RM4I[29], + =RN4HFJ[29],=RN4HIF[29],=RP72AG[30],=RP72I[30],=RP72MF[30],=RP72WO[30],=RP73DD[30],=RP73I[30], + =RP73PM[30],=RP74DD[30],=RP74I[30],=RT9K/4[30],=RU4HD[29],=RU4HP[29],=RU4I[29],=RU9CK/4/M[30], + =RU9SO/M[30],=RV9JD/4/M[30],=RW4HM[29],=RW4HTK[29],=RW4HW[29],=RW4HZ[29],=RW9SW/4[30], + =RW9TP/4[30],=RW9WJ/4[30],=RW9WJ/4/P[30],=RZ4HWF/LH[30],=RZ4HZW/FF[30],=RZ9WU/4/M[30], + =UA0KAO/4[30],=UA0QJA/4[30],=UA4H[29],=UA4HBM[29],=UA4HGL[29],=UA4HIP[29],=UA4HIP/M[30], + =UA4HRZ[29],=UA4HY[29],=UA9JGX/4[30],=UA9LAO/4[30],=UA9SQG/4/P[30],=UA9SY/4[30],=UB5O/M[30], + =UC4I[29],=UI4I[29], =R01DTV/4,=R9XC/4,=RA9XAF/4,=UA4HIP/4,=UA9JFE/4, =R8XF/4,=RA4NCC[30],=RA9FR/4/P,=RA9XSM/4,=RD9CX/4,=RD9CX/4/P,=RU0LM/4,=RW9XC/4/M,=UA4NE/M, =UA4NF[30],=UA4NF/M,=UA9APA/4/P,=UA9FIT/4,=UA9XI/4,=UE9FDA/4,=UE9FDA/4/M,=UE9GDA/4, @@ -2339,15 +2380,16 @@ European Russia: 16: 29: EU: 53.65: -41.37: -4.0: UA: RN4W[30],RO4W[30],RQ4W[30],RT4W[30],RU4W[30],RV4W[30],RW4W[30],RX4W[30],RY4W[30],RZ4W[30],U4W[30], UA4W[30],UB4W[30],UC4W[30],UD4W[30],UE4W[30],UF4W[30],UG4W[30],UH4W[30],UI4W[30],=R0CM/4[30], =R9GM/4[30],=R9UT/4[30],=RA9FDR/4/P[30],=RA9KV/4/M[30],=RA9WU/4[30],=RA9WU/4/M[30],=RA9WU/4/P[30], - =RP72IZ[30],=RP73IZ[30],=RW9FWB/4[30],=RW9FWR/4[30],=RW9FWR/4/M[30],=RX9FW/4[30],=UA9UAX/4/M[30], + =RP72IZ[30],=RP73IZ[30],=RP74IZ[30],=RW9FWB/4[30],=RW9FWR/4[30],=RW9FWR/4/M[30],=RX9FW/4[30], + =UA9UAX/4/M[30], =RT9T/4,=RV9MD/4,=UA4PCM/M,=UE04YCS,=UE85AGN, =R01DTV,=R01DTV/7,=R0IT/6,=R80TV,=R8XW/6,=R9JO/6,=R9KD/6,=R9OM/6,=R9WGM/6/M,=RA0APW/6,=RA0FW/6, =RA0LIF/6,=RA0LLW/6,=RA0QR/6,=RA9ODR/6,=RA9ODR/6/M,=RA9SAS/6,=RA9UWD/6,=RA9WW/6,=RD9CX/6, =RD9CX/6/P,=RK6AH/LH,=RK9JA/6,=RN0CF/6,=RN0JT/6,=RQ0C/6,=RT9K/6,=RT9K/6/P,=RT9K/6/QRP,=RU2FB/6, - =RU9MX/6,=RU9QRP/6/M,=RU9QRP/6/P,=RV9FQ/6,=RW0LIF/6,=RW0LIF/6/LH,=RW6AWW/LH,=RW9JZ/6,=RW9WA/6, - =RX6AA/ANT,=RX6AAP/ANT,=RX9TX/6,=RZ9HG/6,=RZ9HT/6,=RZ9UF/6,=RZ9UZV/6,=UA0AGE/6,=UA0IT/6,=UA0JL/6, - =UA0LQQ/6/P,=UA0SEP/6,=UA2FT/6,=UA6ADC/N,=UA9COO/6,=UA9JON/6,=UA9JPX/6,=UA9KB/6,=UA9KJ/6,=UA9KW/6, - =UA9MQR/6,=UA9UAX/6,=UA9VR/6,=UA9XC/6,=UA9XCI/6,=UB5O/M,=UE9WDA/6,=UE9WFF/6, + =RU9MX/6,=RU9QRP/6/M,=RU9QRP/6/P,=RU9SO/6,=RV9FQ/6,=RW0LIF/6,=RW0LIF/6/LH,=RW6AWW/LH,=RW9JZ/6, + =RW9WA/6,=RX6AA/ANT,=RX6AAP/ANT,=RX9TX/6,=RZ9HG/6,=RZ9HT/6,=RZ9UF/6,=RZ9UZV/6,=UA0AGE/6,=UA0IT/6, + =UA0JL/6,=UA0LQQ/6/P,=UA0SEP/6,=UA2FT/6,=UA6ADC/N,=UA9COO/6,=UA9JON/6,=UA9JPX/6,=UA9KB/6,=UA9KJ/6, + =UA9KW/6,=UA9MQR/6,=UA9UAX/6,=UA9VR/6,=UA9XC/6,=UA9XCI/6,=UE9WDA/6,=UE9WFF/6,=UF0W/6, =RA6EE/FF,=RN7G/FF,=UA0LEC/6,=UA9KAS/6,=UA9KAS/6/P, =R9XV/6,=RA0ZG/6,=RA9CHS/6,=RA9CHS/7,=RK7G/FF,=RM8A/6/M,=RT9K/7,=RU9CK/7,=RU9ZA/7,=RZ7G/FF, =RZ9ON/6,=UA0ZDA/6,=UA0ZS/6,=UA6HBO/N,=UA6HBO/ST30,=UA6IC/6/FF,=UA9CE/6,=UA9UAX/7/M,=UE80HS, @@ -2359,7 +2401,7 @@ European Russia: 16: 29: EU: 53.65: -41.37: -4.0: UA: =R8FF/6,=R9DA/6,=RU9CK/6/P,=RV9CX/6/P,=UA9CES/6,=UA9FGR/6,=UA9WQK/6, =RU9CK/7/M,=RU9CK/7/P,=RV9CX/7/P,=UA9JFN/6/M, =RT9K/7/P,=RZ7G/6/FF, - =R01DTV/6,=RV9AB/6, + =R01DTV/6,=R7AB/P,=RV9AB/6, =R9MJ/6,=R9OM/5/P,=R9XT/6,=RA9KD/6,=RN9N/6,=RT9T/6,=RT9T/6/M,=RU2FB/5,=RU9WW/5/M,=RW9AW/5, =UA0LLM/5,=UA8WAA/5,=UA9CDC/6,=UA9UAX/5,=UE2KR,=UE98PW, =R8AEU/6,=R9MJ/6/M,=RN9N/6/M,=UB8ADI/5,=UB8ADI/6,=UE2SE, @@ -2381,50 +2423,55 @@ European Russia: 16: 29: EU: 53.65: -41.37: -4.0: UA: UE8G(17)[30],UE9F(17)[30],UE9G(17)[30],UF8F(17)[30],UF8G(17)[30],UF9F(17)[30],UF9G(17)[30], UG8F(17)[30],UG8G(17)[30],UG9F(17)[30],UG9G(17)[30],UH8F(17)[30],UH8G(17)[30],UH9F(17)[30], UH9G(17)[30],UI8F(17)[30],UI8G(17)[30],UI9F(17)[30],UI9G(17)[30],=R120RP(17)[30],=R155PM(17)[30], - =R18PER(17)[30],=R2011UFO(17)[30],=R2011UFO/M(17)[30],=R2011UFO/P(17)[30],=R2014WOG(17)[30], - =R20PRM(17)[30],=R2AG/9(17)[30],=R34CZF(17)[30],=R6DAB/9(17)[30],=R8CZ/4(17)[30], - =R8CZ/4/M(17)[30],=R8CZ/M(17)[30],=R95FR(17)[30],=R9CZ/4(17)[30],=R9CZ/4/M(17)[30], - =R9KC/4/M(17)[30],=R9KC/8/M(17)[30],=RA27FM(17)[30],=RA9XAI/4(17)[30],=RC20FM(17)[30], - =RD4M/9(17)[30],=RG50P/M(17)[30],=RP70PK(17)[30],=RP9FKU(17)[30],=RP9FTK(17)[30],=RU27FQ(17)[30], - =RU27FW(17)[30],=RU4W/9(17)[30],=RV22PM(17)[30],=RX9TX/9(17)[30],=RZ16FM(17)[30],=RZ9WM/9(17)[30], - =UA1ZQO/9(17)[30],=UA4NF/4/M(17)[30],=UA4WA/9(17)[30],=UA9CGL/4/M(17)[30],=UA9CUA/4/M(17)[30], - =UA9UAX/4(17)[30],=UE16SA(17)[30],=UE55PM(17)[30], + =R160PM(17)[30],=R18PER(17)[30],=R2011UFO(17)[30],=R2011UFO/M(17)[30],=R2011UFO/P(17)[30], + =R2014WOG(17)[30],=R20PRM(17)[30],=R2AG/9(17)[30],=R34CZF(17)[30],=R6DAB/9(17)[30], + =R8CZ/4(17)[30],=R8CZ/4/M(17)[30],=R8CZ/M(17)[30],=R95FR(17)[30],=R9CZ/4(17)[30], + =R9CZ/4/M(17)[30],=R9KC/4/M(17)[30],=R9KC/8/M(17)[30],=RA27FM(17)[30],=RA9XAI/4(17)[30], + =RC20FM(17)[30],=RD4M/9(17)[30],=RG50P/M(17)[30],=RN9N/4(17)[30],=RP70PK(17)[30],=RP9FKU(17)[30], + =RP9FTK(17)[30],=RU27FQ(17)[30],=RU27FW(17)[30],=RU4W/9(17)[30],=RV22PM(17)[30],=RX9TX/9(17)[30], + =RZ16FM(17)[30],=RZ9WM/9(17)[30],=UA1ZQO/9(17)[30],=UA3FQ/4(17)[30],=UA3FQ/4/P(17)[30], + =UA4NF/4/M(17)[30],=UA4WA/9(17)[30],=UA9CGL/4/M(17)[30],=UA9CUA/4/M(17)[30],=UA9UAX/4(17)[30], + =UE16SA(17)[30],=UE55PM(17)[30], =RW3TN/9(17)[30],=UE10SK(17)[30], - R8X(17)[20],R9X(17)[20],RA8X(17)[20],RA9X(17)[20],RC8X(17)[20],RC9X(17)[20],RD8X(17)[20], - RD9X(17)[20],RE8X(17)[20],RE9X(17)[20],RF8X(17)[20],RF9X(17)[20],RG8X(17)[20],RG9X(17)[20], - RI8X(17)[20],RI9X(17)[20],RJ8X(17)[20],RJ9X(17)[20],RK8X(17)[20],RK9X(17)[20],RL8X(17)[20], - RL9X(17)[20],RM8X(17)[20],RM9X(17)[20],RN8X(17)[20],RN9X(17)[20],RO8X(17)[20],RO9X(17)[20], - RQ8X(17)[20],RQ9X(17)[20],RT8X(17)[20],RT9X(17)[20],RU8X(17)[20],RU9X(17)[20],RV8X(17)[20], - RV9X(17)[20],RW8X(17)[20],RW9X(17)[20],RX8X(17)[20],RX9X(17)[20],RY8X(17)[20],RY9X(17)[20], - RZ8X(17)[20],RZ9X(17)[20],U8X(17)[20],U9X(17)[20],UA8X(17)[20],UA9X(17)[20],UB8X(17)[20], - UB9X(17)[20],UC8X(17)[20],UC9X(17)[20],UD8X(17)[20],UD9X(17)[20],UE8X(17)[20],UE9X(17)[20], - UF8X(17)[20],UF9X(17)[20],UG8X(17)[20],UG9X(17)[20],UH8X(17)[20],UH9X(17)[20],UI8X(17)[20], - UI9X(17)[20],=R100AP(17)[20],=R120RK(17)[20],=R16NOR(17)[20],=R18ISL(17)[20],=R2014I(17)[20], - =R20SZO(17)[20],=R35MWC(17)[20],=R3RRC/9(17)[20],=R5QA/1(17)[20],=R5QQ/1(17)[20], - =R6DGL/9/M(17)[20],=R70SRC(17)[20],=R7BA/1(17)[20],=R7BA/9(17)[20],=R7BA/9/M(17)[20], - =R8FF/P(17)[20],=R8MB/1(17)[20],=R8MB/1/P(17)[20],=R9/UR7IMG(17)[20],=R95KOMI(17)[20], - =R9KD/9(17)[20],=R9XAK/1/P(17)[20],=RA/DK5JI(17)[20],=RA/UR5MKH(17)[20],=RA22KO(17)[20], - =RA22XA(17)[20],=RA22XF(17)[20],=RA22XU(17)[20],=RA3AMG/9/M(17)[20],=RA3OM/9(17)[20], - =RA4NH/9(17)[20],=RA4NV/9(17)[20],=RA6ACI/9(17)[20],=RD4CBQ/9(17)[20],=RK1OWZ/9(17)[20], - =RK1OWZ/9/M(17)[20],=RK6K/9(17)[20],=RK90DR(17)[20],=RN22OG(17)[20],=RN22OV(17)[20], - =RN4ACZ/9(17)[20],=RO25KO(17)[20],=RP67KR(17)[20],=RP68KR(17)[20],=RP70KW(17)[20],=RP71KW(17)[20], - =RP72X(17)[20],=RP73X(17)[20],=RT73LF(17)[20],=RV3UI/9(17)[20],=RW1QN/9(17)[20], - =RW1QN/9/M(17)[20],=RW1QN/9/P(17)[20],=RW4NJ/9/M(17)[20],=RY110RAEM(17)[20],=UA1OOX/9(17)[20], - =UA1QV/9(17)[20],=UA3FQ/4(17)[20],=UA4WP/9/M(17)[20],=UA6LTO/9(17)[20],=UB1OAD/1/P(17)[20], - =UB1OAD/9/P(17)[20],=UB5O/1/M(17)[20],=UE16ST(17)[20],=UE1RDA/9(17)[20],=UE85DRK(17)[20], - =UE90K(17)[20]; + R1I(17)[20],R8X(17)[20],R9X(17)[20],RA1I(17)[20],RA8X(17)[20],RA9X(17)[20],RC1I(17)[20], + RC8X(17)[20],RC9X(17)[20],RD1I(17)[20],RD8X(17)[20],RD9X(17)[20],RE1I(17)[20],RE8X(17)[20], + RE9X(17)[20],RF1I(17)[20],RF8X(17)[20],RF9X(17)[20],RG1I(17)[20],RG8X(17)[20],RG9X(17)[20], + RI8X(17)[20],RI9X(17)[20],RJ1I(17)[20],RJ8X(17)[20],RJ9X(17)[20],RK1I(17)[20],RK8X(17)[20], + RK9X(17)[20],RL1I(17)[20],RL8X(17)[20],RL9X(17)[20],RM1I(17)[20],RM8X(17)[20],RM9X(17)[20], + RN1I(17)[20],RN8X(17)[20],RN9X(17)[20],RO1I(17)[20],RO8X(17)[20],RO9X(17)[20],RQ1I(17)[20], + RQ8X(17)[20],RQ9X(17)[20],RT1I(17)[20],RT8X(17)[20],RT9X(17)[20],RU1I(17)[20],RU8X(17)[20], + RU9X(17)[20],RV1I(17)[20],RV8X(17)[20],RV9X(17)[20],RW1I(17)[20],RW8X(17)[20],RW9X(17)[20], + RX1I(17)[20],RX8X(17)[20],RX9X(17)[20],RY1I(17)[20],RY8X(17)[20],RY9X(17)[20],RZ1I(17)[20], + RZ8X(17)[20],RZ9X(17)[20],U1I(17)[20],U8X(17)[20],U9X(17)[20],UA1I(17)[20],UA8X(17)[20], + UA9X(17)[20],UB1I(17)[20],UB8X(17)[20],UB9X(17)[20],UC1I(17)[20],UC8X(17)[20],UC9X(17)[20], + UD1I(17)[20],UD8X(17)[20],UD9X(17)[20],UE1I(17)[20],UE8X(17)[20],UE9X(17)[20],UF1I(17)[20], + UF8X(17)[20],UF9X(17)[20],UG1I(17)[20],UG8X(17)[20],UG9X(17)[20],UH1I(17)[20],UH8X(17)[20], + UH9X(17)[20],UI1I(17)[20],UI8X(17)[20],UI9X(17)[20],=R100AP(17)[20],=R120RK(17)[20], + =R16NOR(17)[20],=R18ISL(17)[20],=R2014I(17)[20],=R20SZO(17)[20],=R35MWC(17)[20],=R3RRC/9(17)[20], + =R5QA/1(17)[20],=R5QQ/1(17)[20],=R6DGL/9/M(17)[20],=R70SRC(17)[20],=R7BA/1(17)[20], + =R7BA/9(17)[20],=R7BA/9/M(17)[20],=R8FF/P(17)[20],=R8MB/1(17)[20],=R8MB/1/P(17)[20], + =R9/UR7IMG(17)[20],=R95KOMI(17)[20],=R9KD/9(17)[20],=R9XAK/1/P(17)[20],=RA/DK5JI(17)[20], + =RA/UR5MKH(17)[20],=RA22KO(17)[20],=RA22XA(17)[20],=RA22XF(17)[20],=RA22XU(17)[20], + =RA3AMG/9/M(17)[20],=RA3OM/9(17)[20],=RA3X/1(17)[20],=RA4NH/9(17)[20],=RA4NV/9(17)[20], + =RA6ACI/9(17)[20],=RD4CBQ/9(17)[20],=RK1OWZ/9(17)[20],=RK1OWZ/9/M(17)[20],=RK6K/9(17)[20], + =RK90DR(17)[20],=RN22OG(17)[20],=RN22OV(17)[20],=RN4ACZ/9(17)[20],=RO25KO(17)[20],=RP67KR(17)[20], + =RP68KR(17)[20],=RP70KW(17)[20],=RP71KW(17)[20],=RP72X(17)[20],=RP73X(17)[20],=RP74X(17)[20], + =RT73LF(17)[20],=RV3UI/9(17)[20],=RW1QN/9(17)[20],=RW1QN/9/M(17)[20],=RW1QN/9/P(17)[20], + =RW4NJ/9/M(17)[20],=RY110RAEM(17)[20],=UA1OOX/9(17)[20],=UA1QV/9(17)[20],=UA4WP/9/M(17)[20], + =UA6LTO/9(17)[20],=UB1OAD/1/P(17)[20],=UB1OAD/9/P(17)[20],=UB5O/1/M(17)[20],=UE16ST(17)[20], + =UE1RDA/9(17)[20],=UE85DRK(17)[20],=UE90K(17)[20]; Kaliningrad: 15: 29: EU: 54.72: -20.52: -3.0: UA2: R2F,R2K,RA2,RC2F,RC2K,RD2F,RD2K,RE2F,RE2K,RF2F,RF2K,RG2F,RG2K,RJ2F,RJ2K,RK2F,RK2K,RL2F,RL2K,RM2F, RM2K,RN2F,RN2K,RO2F,RO2K,RQ2F,RQ2K,RT2F,RT2K,RU2F,RU2K,RV2F,RV2K,RW2F,RW2K,RX2F,RX2K,RY2F,RY2K, RZ2F,RZ2K,U2F,U2K,UA2,UB2,UC2,UD2,UE2,UF2,UG2,UH2,UI2,=R01DTV/2,=R10RLHA/2,=R10RTRS/2,=R1255F, =R1336FO,=R14CWC/2,=R15CWC/2,=R15CWC/2/QRP,=R18SRB,=R1NW/2,=R1QAP/2,=R2/DK2AI,=R2/DL1YMK, =R2/N6TCZ,=R2/R6AF,=R2/UA6LV,=R2/UR0MC,=R21GGGR,=R22GGGR,=R22GGR,=R25ARCK/2,=R2MWO,=R310A/2, - =R3SRR/2,=R3XA/2,=R5K/2,=R5QA/2,=R60A,=R680FBO,=R6AF/2,=R7LV/2,=R900BL/2,=RA/DL6KV,=RA/EU1FY/P, - =RA2FDX/FF,=RA2FN/RP,=RA2FO/N,=RA3ATX/2,=RA3XM/2,=RA4LW/2,=RC18KA,=RD22FU,=RD3FG/2,=RJ22DX, - =RK3QS/2,=RM9I/2,=RM9IX/2,=RN3GM/2,=RP2F,=RP2K,=RP70KB,=RP70KG,=RP70MW,=RP70WB,=RT9T/2,=RU3FS/2, - =RU5A/2,=RV3FF/2,=RV3MA/2,=RV3UK/2,=RV9WZ/2,=RW9QA/2,=RY1AAA/2,=RZ3FA/2,=RZ6HB/2,=UA0SIK/2, - =UA1AAE/2,=UA1AFT/2,=UA2DC/RP,=UA2FM/MM(13),=UA3DJG/2,=UA4RC/2,=UA4WHX/2,=UA9UAX/2,=UB5O/2, - =UB5O/2/M,=UB9KAA/2,=UE08F,=UE1RLH/2,=UE3QRP/2,=UE6MAC/2,=UF1M/2; + =R3SRR/2,=R3XA/2,=R5K/2,=R5QA/2,=R60A,=R680FBO,=R6AF/2,=R777AN,=R7LV/2,=R900BL/2,=RA/DL6KV, + =RA/EU1FY/P,=RA2FDX/FF,=RA2FN/RP,=RA2FO/N,=RA3ATX/2,=RA3XM/2,=RA4LW/2,=RC18KA,=RD22FU,=RD3FG/2, + =RJ22DX,=RK3QS/2,=RM9I/2,=RM9IX/2,=RN3GM/2,=RP2F,=RP2K,=RP70KB,=RP70KG,=RP70MW,=RP70WB,=RT9T/2, + =RU3FS/2,=RU5A/2,=RV3FF/2,=RV3MA/2,=RV3UK/2,=RV9WZ/2,=RW9QA/2,=RY1AAA/2,=RZ3FA/2,=RZ6HB/2, + =UA0SIK/2,=UA1AAE/2,=UA1AFT/2,=UA2DC/RP,=UA2FM/MM(13),=UA3DJG/2,=UA4RC/2,=UA4WHX/2,=UA9UAX/2, + =UB5O/2,=UB5O/2/M,=UB9KAA/2,=UE08F,=UE1RLH/2,=UE3QRP/2,=UE6MAC/2,=UF1M/2; Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: R0(19)[33],R8,R9,RA0(19)[33],RA8,RA9,RC0(19)[33],RC8,RC9,RD0(19)[33],RD8,RD9,RE0(19)[33],RE8,RE9, RF0(19)[33],RF8,RF9,RG0(19)[33],RG8,RG9,RI0(19)[33],RI8,RI9,RJ0(19)[33],RJ8,RJ9,RK0(19)[33],RK8, @@ -2438,26 +2485,28 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: =RA4AAJ/9(18),=RD17CW(19),=RD1AL/0(40)[75],=RD3ARX/0/P(19),=RI18POL(40)[75],=RJ17WG,=RL19WF, =RM17NY,=RM19WF(18),=RN17CW,=RO19WF(19),=RQ17CW(18),=RQ17WG,=RQ4D/9(18),=RU17NY(18),=RV3PZ/9, =RW1AI/0(19),=RW55YG,=RX17WG(19),=RX55YG(18),=RX80SP(18),=RY1AAB/0/M(19),=RY80SP(19),=RZ17NY(19), - =RZ6A/9,=RZ9YI/9,=UA0ZDA/MM(29),=UA3DND/8,=UA3TT/8,=UE18M,=UE18U(18),=UE18Z(19), + =RZ6A/9,=RZ9YI/9,=UA0ZDA/MM(29),=UA3DND/8,=UA3TT/8,=UD6AOP/0(19),=UE18M,=UE18U(18),=UE18Z(19), =R100RG,=R120RG,=R2014Y,=R2015TL,=R20UFO,=R22SKE,=R280A,=R280B,=R3HD/9,=R3RRC/8,=R55TV,=R6RA/9, =R70PW,=R70PW/P,=R9SRR,=RA1AIP/9/P,=RA1AR/9,=RA1QR/9,=RA3WJ/9,=RA3XBN/9,=RA3ZM/8,=RA4FSC/9, =RA4HGN/9,=RA9SC/9,=RA9WJV/8/P,=RC20AB,=RC20AC,=RD3BN/9,=RD4CAQ/9,=RG110RAEM,=RJ17CW,=RK9SZZ/9, =RL5G/8,=RL9AA/P,=RN4WA/9,=RN9O/8,=RP67TG,=RP68MZ,=RP70AZ,=RP70PM,=RP70TG,=RP71AZ,=RP71TG,=RP72AZ, - =RP72MS,=RP72TG,=RP73AZ,=RP73TG,=RP73U,=RQ4D/8,=RT60RT,=RT73AB,=RU22AZ,=RV1AQ/9,=RV1CC/8,=RV1CC/9, - =RV3BA/9,=RV9WB/9/M,=RV9WMZ/9/P,=RV9WMZ/P,=RX3RC/9,=RX9WN/9/M,=RZ0OO/9,=RZ6DR/9/M,=RZ9OO/9/M, - =UA0MF/9,=UA3AKO/8,=UA4RC/9,=UA6A/9,=UA6CW/9,=UA6YGY/8,=UA6YGY/9,=UA8WAA/9,=UA8WAA/9/P,=UA8WAA/M, - =UA9CGL/9/M,=UA9SG/9,=UA9TO/9/M,=UA9WMN/9/P,=UB5O/8,=UE45AWT,=UE70AAA,=UE9WDA/9, - =R01DTV/8,=R14CWC/8,=R14CWC/9,=R150DMP,=R155AP,=R15CWC/8,=R15CWC/8/QRP,=R16SVK,=R170GS/8,=R2015BP, - =R2015R,=R2016DR,=R20EKB,=R22SKJ,=R27EKB,=R30ZF,=R35CZF,=R375I,=R44YETI/8,=R4WAB/9/P,=R55EPC, - =R55EPC/P,=R6UAE/9,=R70NIK,=R7LZ/8,=R8FF/8,=R9GM/8,=R9GM/8/M,=RA/DL6XK,=RA/US5ETV,=RA0BA/8, - =RA0BA/9,=RA27AA,=RA27EK,=RA36GS,=RA36ZF,=RA4YW/9,=RA4YW/9/M,=RA9FW/9,=RA9WU/9,=RC18EK,=RD0B/8, - =RK9AD/9/M,=RK9DR/N,=RM0B/9,=RM19NY,=RN16CW,=RN3QBG/9,=RP68DT,=RP68RG,=RP68TG,=RP68TK,=RP69GR, - =RP70DT,=RP70G,=RP70GB,=RP70GR,=RP70MA,=RP70SA,=RP70UH,=RP71DT,=RP71GA,=RP71GA/M,=RP71GB,=RP71GR, - =RP71LT,=RP71MO,=RP71SA,=RP72DT,=RP72FI,=RP72GB,=RP72GR,=RP72IM,=RP72KB,=RP72SA,=RP73DT,=RP73GB, - =RP73GR,=RP73IM,=RP73SA,=RT4C/8,=RT4W/9,=RT73BR,=RT73EB,=RT73FL,=RT73HE,=RT73KB,=RT73SK,=RU22CR, - =RU5D/8,=RU5D/9,=RV6LGY/9,=RV6LGY/9/M,=RV6LGY/9/P,=RV6MD/9,=RW4NX/9,=RW9C[20],=RX0SD/9,=RX3Q/9, - =RX9UL/9,=RY9C/P,=RZ37ZF,=RZ38ZF,=RZ39ZF,=UA0BA/8,=UA3FQ/8,=UA3IHJ/8,=UA4WHX/9,=UA8WAA/8,=UA9MW/9, - =UA9UAX/8,=UA9UAX/8/M,=UE16SR,=UE25F,=UE40CZF,=UE4NFF/9,=UE56S,=UE64RWA,=UE70SL,=UE75DT, + =RP72MS,=RP72TG,=RP73AZ,=RP73TG,=RP73U,=RP74AZ,=RP74TG,=RP74U,=RQ4D/8,=RT60RT,=RT73AB,=RU22AZ, + =RV1AQ/9,=RV1CC/8,=RV1CC/9,=RV3BA/9,=RV9WB/9/M,=RV9WMZ/9/P,=RV9WMZ/P,=RX3RC/9,=RX9WN/9/M,=RZ0OO/9, + =RZ6DR/9/M,=RZ9OO/9/M,=UA0MF/9,=UA3AKO/8,=UA4RC/9,=UA6A/9,=UA6CW/9,=UA6YGY/8,=UA6YGY/9,=UA8WAA/9, + =UA8WAA/9/P,=UA8WAA/M,=UA9CGL/9/M,=UA9SG/9,=UA9TO/9/M,=UA9WMN/9/P,=UB5O/8,=UE45AWT,=UE70AAA, + =UE9WDA/9, + =R01DTV/8,=R14CWC/8,=R14CWC/9,=R150DMP,=R155AP,=R15CWC/8,=R15CWC/8/QRP,=R160DMP,=R16SVK,=R170GS/8, + =R2015BP,=R2015R,=R2016DR,=R20EKB,=R22SKJ,=R27EKB,=R30ZF,=R35CZF,=R375I,=R44YETI/8,=R4WAB/9/P, + =R55EPC,=R55EPC/P,=R6UAE/9,=R70NIK,=R7LZ/8,=R8FF/8,=R9GM/8,=R9GM/8/M,=RA/DL6XK,=RA/US5ETV, + =RA0BA/8,=RA0BA/9,=RA27AA,=RA27EK,=RA36GS,=RA36ZF,=RA4YW/9,=RA4YW/9/M,=RA9FW/9,=RA9WU/9,=RC18EK, + =RD0B/8,=RK9AD/9/M,=RK9DR/N,=RM0B/9,=RM19NY,=RN16CW,=RN3QBG/9,=RP68DT,=RP68RG,=RP68TG,=RP68TK, + =RP69GR,=RP70DT,=RP70G,=RP70GB,=RP70GR,=RP70MA,=RP70SA,=RP70UH,=RP71DT,=RP71GA,=RP71GA/M,=RP71GB, + =RP71GR,=RP71LT,=RP71MO,=RP71SA,=RP72DT,=RP72FI,=RP72GB,=RP72GR,=RP72IM,=RP72KB,=RP72SA,=RP73DT, + =RP73GB,=RP73GR,=RP73IM,=RP73SA,=RP74DT,=RP74GB,=RP74GR,=RP74IM,=RT4C/8,=RT4W/9,=RT73BR,=RT73EB, + =RT73FL,=RT73HE,=RT73KB,=RT73SK,=RU22CR,=RU5D/8,=RU5D/9,=RV6LGY/9,=RV6LGY/9/M,=RV6LGY/9/P, + =RV6MD/9,=RW4NX/9,=RW9C[20],=RX0SD/9,=RX3Q/9,=RX9UL/9,=RY9C/P,=RZ1CWC/8,=RZ37ZF,=RZ38ZF,=RZ39ZF, + =UA0BA/8,=UA3FQ/8,=UA3IHJ/8,=UA4WHX/9,=UA8WAA/8,=UA9MW/9,=UA9UAX/8,=UA9UAX/8/M,=UE16SR,=UE25F, + =UE40CZF,=UE4NFF/9,=UE56S,=UE64RWA,=UE70SL,=UE75DT, R8H(18)[31],R8I(18)[31],R9H(18)[31],R9I(18)[31],RA8H(18)[31],RA8I(18)[31],RA9H(18)[31], RA9I(18)[31],RC8H(18)[31],RC8I(18)[31],RC9H(18)[31],RC9I(18)[31],RD8H(18)[31],RD8I(18)[31], RD9H(18)[31],RD9I(18)[31],RE8H(18)[31],RE8I(18)[31],RE9H(18)[31],RE9I(18)[31],RF8H(18)[31], @@ -2487,15 +2536,15 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: RU9J[20],RV8J[20],RV9J[20],RW8J[20],RW9J[20],RX8J[20],RX9J[20],RY8J[20],RY9J[20],RZ8J[20], RZ9J[20],U8J[20],U9J[20],UA8J[20],UA9J[20],UB8J[20],UB9J[20],UC8J[20],UC9J[20],UD8J[20],UD9J[20], UE8J[20],UE9J[20],UF8J[20],UF9J[20],UG8J[20],UG9J[20],UH8J[20],UH9J[20],UI8J[20],UI9J[20], - =R120RJ[20],=R123JDR[20],=R15UGRA[20],=R16UGRA[20],=R18KSA[20],=R25ARCK/8[20],=R2AEA/9[20], - =R4YAC/9[20],=R8JAJ/M[20],=RA/UR8IF[20],=RA/UT2LA[20],=RA1QBH/9[20],=RA3ARS/9[20],=RA3ARS/9/M[20], - =RA3QQI/8[20],=RA4FCJ/9[20],=RA4HRM/9[20],=RA9WN/9[20],=RD4HM/9[20],=RJ9J[20],=RK4PA/9[20], - =RK6ANP/9[20],=RK6YM/8[20],=RK6YM/9[20],=RP67GS[20],=RP68GS[20],=RP68J[20],=RP68LK[20], - =RP69GS[20],=RP69SF[20],=RP70GS[20],=RP70LF[20],=RP70SF[20],=RP70SU[20],=RP70YF[20],=RP71GS[20], - =RP71LF[20],=RP71SF[20],=RP72DS[20],=RP72GS[20],=RP72SF[20],=RP72YF[20],=RP73GS[20],=RP73SF[20], - =RQ0C/8[20],=RU6YD/9[20],=RV6YM/9[20],=RW4HOH/9[20],=RW4LX/9[20],=RW6AHV/9[20],=RW9WX/9[20], - =RX3BP/9[20],=RX3BP/9/MM[20],=RZ5D/8[20],=RZ9WF/8[20],=RZ9WF/9[20],=UA3ZAF/9[20],=UA6WIO/9[20], - =UA9JFN/M[20], + =R11UND[20],=R120RJ[20],=R123JDR[20],=R15UGRA[20],=R16UGRA[20],=R18KSA[20],=R25ARCK/8[20], + =R2AEA/9[20],=R4YAC/9[20],=R8JAJ/M[20],=RA/UR8IF[20],=RA/UT2LA[20],=RA1QBH/9[20],=RA3ARS/9[20], + =RA3ARS/9/M[20],=RA3QQI/8[20],=RA4FCJ/9[20],=RA4HRM/9[20],=RA60PD[20],=RA9WN/9[20],=RD4HM/9[20], + =RJ9J[20],=RK4PA/9[20],=RK6ANP/9[20],=RK6YM/8[20],=RK6YM/9[20],=RP67GS[20],=RP68GS[20],=RP68J[20], + =RP68LK[20],=RP69GS[20],=RP69SF[20],=RP70GS[20],=RP70LF[20],=RP70SF[20],=RP70SU[20],=RP70YF[20], + =RP71GS[20],=RP71LF[20],=RP71SF[20],=RP72DS[20],=RP72GS[20],=RP72SF[20],=RP72YF[20],=RP73GS[20], + =RP73SF[20],=RP74GS[20],=RQ0C/8[20],=RU6YD/9[20],=RV6YM/9[20],=RW4HOH/9[20],=RW4LX/9[20], + =RW6AHV/9[20],=RW9WX/9[20],=RX3BP/9[20],=RX3BP/9/MM[20],=RZ5D/8[20],=RZ9WF/8[20],=RZ9WF/9[20], + =UA3ZAF/9[20],=UA6WIO/9[20],=UA9JFN/M[20], R8K[20],R9K[20],RA8K[20],RA9K[20],RC8K[20],RC9K[20],RD8K[20],RD9K[20],RE8K[20],RE9K[20],RF8K[20], RF9K[20],RG8K[20],RG9K[20],RI9K[20],RJ8K[20],RJ9K[20],RK8K[20],RK9K[20],RL8K[20],RL9K[20], RM8K[20],RM9K[20],RN8K[20],RN9K[20],RO8K[20],RO9K[20],RQ8K[20],RQ9K[20],RT8K[20],RT9K[20], @@ -2511,16 +2560,16 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: =UA1FBP/9[20],=UA1PBA/9[20],=UA1PBP/9[20],=UA3DFM/8[20],=UA3DFM/9[20],=UA3MGA/9[20],=UA6BTN/9[20], =UA9SUV/8[20], =R11QRP/8,=R11QRP/8/P,=R120RL,=R18POR,=R2015EP,=R2015LY,=R2015LY/8,=R22BIA,=R30STM,=R430LT, - =R4FAA/8,=R8MC/9,=R8MD/9,=RA/EW8ADX,=RA0UAC/8,=RA0UF/8,=RA3CW/9,=RA9JG/9,=RC1M/8/M,=RN9N/M, - =RO25TN,=RP67JH,=RP67LK,=RP67LL,=RP67TT,=RP68LS,=RP68TT,=RP69CM,=RP69DK,=RP69GP,=RP69LK,=RP69LL, - =RP69LS,=RP69MM,=RP69P,=RP69YN,=RP70GP,=RP70LL,=RP70LM,=RP70P,=RP70TM,=RP71GP,=RP71LL,=RP71P, - =RP72GP,=RP72LL,=RP72P,=RP72PJ,=RP73LL,=RP73P,=RR110RAEM,=RU22LR,=RW0QJ/9,=RX4W/8,=RX6DL/8, + =R4FAA/8,=R8MC/9,=R8MD/9,=RA/EW8ADX,=RA0UAC/8,=RA0UF/8,=RA3CW/9,=RA9JG/9,=RC1M/8/M,=RO25TN, + =RP67JH,=RP67LK,=RP67LL,=RP67TT,=RP68LS,=RP68TT,=RP69CM,=RP69DK,=RP69GP,=RP69LK,=RP69LL,=RP69LS, + =RP69MM,=RP69P,=RP69YN,=RP70GP,=RP70LL,=RP70LM,=RP70P,=RP70TM,=RP71GP,=RP71LL,=RP71P,=RP72GP, + =RP72LL,=RP72P,=RP72PJ,=RP73LL,=RP73P,=RP74LL,=RP74P,=RR110RAEM,=RU22LR,=RW0QJ/9,=RX4W/8,=RX6DL/8, =RX6DL/8/P,=RX6DL/8/P/QRP,=RX6DL/9/P,=RZ9MXM/9/M,=UB5O/8/P,=UE44Y/8,=UE9FDA/9/M,=UE9MDA/9, =R16CAN,=R1716K,=R1716M,=R1716O,=R1716S,=R9MJ/M,=RA22MX,=RA4CQ/9/M,=RA9MR/0,=RA9MX/P,=RC20MX, - =RK6YYA/9,=RN0SZ/9,=RN9N/9,=RP65MOH,=RP67MC,=RP67MD,=RP68MC,=RP68MD,=RP69MC,=RP69MD,=RP70GK, - =RP70MC,=RP70MD,=RP70OB,=RP70OF,=RP70OS,=RP71GK,=RP71MJ,=RP71OB,=RP72GK,=RP72MJ,=RP72OB,=RP72ZW, - =RP73GK,=RP73OB,=RP8M,=RT22MC,=RT22MD,=RV0SR/9,=RW22MW,=RY22MC,=UA1ZGD/9,=UA3AKO/9,=UA9UAX/M, - =UE55OM,=UE70KRM/9,=UE70KRM/9/M,=UE9OFF/9, + =RK6YYA/9,=RN0SZ/9,=RN9N/9,=RN9N/M,=RP65MOH,=RP67MC,=RP67MD,=RP68MC,=RP68MD,=RP69MC,=RP69MD, + =RP70GK,=RP70MC,=RP70MD,=RP70OB,=RP70OF,=RP70OS,=RP71GK,=RP71MJ,=RP71OB,=RP72GK,=RP72MJ,=RP72OB, + =RP72ZW,=RP73GK,=RP73OB,=RP74PO,=RP8M,=RT22MC,=RT22MD,=RV0SR/9,=RW22MW,=RY22MC,=UA1ZGD/9, + =UA3AKO/9,=UA9MA/M,=UE55OM,=UE70KRM/9,=UE70KRM/9/M,=UE9OFF/9, R8O(18)[31],R8P(18)[31],R9O(18)[31],R9P(18)[31],RA8O(18)[31],RA8P(18)[31],RA9O(18)[31], RA9P(18)[31],RC8O(18)[31],RC8P(18)[31],RC9O(18)[31],RC9P(18)[31],RD8O(18)[31],RD8P(18)[31], RD9O(18)[31],RD9P(18)[31],RE8O(18)[31],RE8P(18)[31],RE9O(18)[31],RE9P(18)[31],RF8O(18)[31], @@ -2547,14 +2596,14 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: =RA27OM(18)[31],=RA3DH/9(18)[31],=RA3ET/9(18)[31],=RA4FRH/0/P(18)[31],=RA9JJ/9/M(18)[31], =RA9MX/9(18)[31],=RC1M/9(18)[31],=RC1M/9/M(18)[31],=RG9O(18)[31],=RN9N/9/M(18)[31],=RO9O(18)[31], =RP67MP(18)[31],=RP68MP(18)[31],=RP70MP(18)[31],=RP71MP(18)[31],=RP72MP(18)[31],=RP73MP(18)[31], - =RP9OMP(18)[31],=RP9OW(18)[31],=RQ16CW(18)[31],=RR9O(18)[31],=RS9O(18)[31],=RU0ZM/9(18)[31], - =RU27OZ(18)[31],=RU6LA/9(18)[31],=RV0CJ/9(18)[31],=RW1AC/9(18)[31],=RW9MD/9/M(18)[31], - =RZ9MXM/9(18)[31],=UA0KDR/9(18)[31],=UA0ZAY/9(18)[31],=UA6WFO/9(18)[31],=UA9MA/9(18)[31], - =UA9MA/9/M(18)[31],=UA9MRA/9(18)[31],=UE80NSO(18)[31], - =R110RP,=R120RDP,=R120RZ,=R120TM,=R150RP,=R155RP,=R18URU,=RA22QF,=RC20QA,=RC20QC,=RC20QF,=RM20CC, - =RM9RZ/A,=RM9RZ/P,=RP65R,=RP67KE,=RP67R,=RP68KE,=RP68R,=RP69KE,=RP69R,=RP70KE,=RP70R,=RP71R, - =RP72KE,=RP72R,=RT73CW,=RT73JH,=RV3MN/9,=RW22QA,=RW22QA/8,=RW22QC,=RW22QC/8,=RW4NW/9,=RY22RZ, - =RZ9WM/9/M,=UE4WFF/9,=UE4WFF/9/P,=UE70KRM/8/M, + =RP74MP(18)[31],=RP9OMP(18)[31],=RP9OW(18)[31],=RQ16CW(18)[31],=RR9O(18)[31],=RS9O(18)[31], + =RU0ZM/9(18)[31],=RU27OZ(18)[31],=RU6LA/9(18)[31],=RV0CJ/9(18)[31],=RW1AC/9(18)[31], + =RW9MD/9/M(18)[31],=RZ9MXM/9(18)[31],=UA0KDR/9(18)[31],=UA0ZAY/9(18)[31],=UA6WFO/9(18)[31], + =UA9MA/9(18)[31],=UA9MA/9/M(18)[31],=UA9MRA/9(18)[31],=UE80NSO(18)[31], + =R110RP,=R120RDP,=R120RZ,=R120TM,=R150RP,=R155RP,=R160RP,=R18URU,=RA22QF,=RC20QA,=RC20QC,=RC20QF, + =RM20CC,=RM9RZ/A,=RM9RZ/P,=RP65R,=RP67KE,=RP67R,=RP68KE,=RP68R,=RP69KE,=RP69R,=RP70KE,=RP70R, + =RP71R,=RP72KE,=RP72R,=RT73CW,=RT73JH,=RV3MN/9,=RW22QA,=RW22QA/8,=RW22QC,=RW22QC/8,=RW4NW/9, + =RY22RZ,=RZ9WM/9/M,=UE4WFF/9,=UE4WFF/9/P,=UE70KRM/8/M, R8S(16),R8T(16),R9S(16),R9T(16),RA8S(16),RA8T(16),RA9S(16),RA9T(16),RC8S(16),RC8T(16),RC9S(16), RC9T(16),RD8S(16),RD8T(16),RD9S(16),RD9T(16),RE8S(16),RE8T(16),RE9S(16),RE9T(16),RF8S(16), RF8T(16),RF9S(16),RF9T(16),RG8S(16),RG8T(16),RG9S(16),RG9T(16),RJ8S(16),RJ8T(16),RJ9S(16), @@ -2572,7 +2621,7 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: =RA9CS/P(16),=RC20OB(16),=RC20TT(16),=RN3DHB/9(16),=RN3DHB/9/P(16),=RN3GW/8(16),=RN3GW/8/QRP(16), =RN3GW/9(16),=RN3GW/9/QRP(16),=RN3QOP/9(16),=RN9S(16),=RN9SM/P(16),=RN9WWW/9(16),=RO9S(16), =RP65TT(16),=RP68GR(16),=RP69NB(16),=RP71TK(16),=RP9SBO(16),=RP9SBR(16),=RP9SNK(16),=RT22TK(16), - =RT73OA(16),=RT8T(16),=RT9S(16),=RT9T(16),=RU22TU(16),=RU9SO/M(16),=RV1CC/4/M(16),=RV9WGF/4/M(16), + =RT73OA(16),=RT8T(16),=RT9S(16),=RT9T(16),=RU22TU(16),=RV1CC/4/M(16),=RV9WGF/4/M(16), =RV9WMZ/9/M(16),=RW4PJZ/9(16),=RW4PJZ/9/M(16),=RW4PP/9(16),=RW9WA/9(16),=RW9WA/9/M(16), =RY4W/9(16),=RZ4HZW/9/M(16),=UA0AGA/9/P(16),=UA0KBA/9(16),=UA3WB/9(16),=UA4LCQ/9(16), =UA9SIV/9(16),=UB5O/4(16),=UB9JBN/9/M(16),=UE1RFF/9(16),=UE25ST(16),=UE55OB(16),=UE60TDP(16), @@ -2596,34 +2645,35 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: UG8U(18)[31],UG8V(18)[31],UG9U(18)[31],UG9V(18)[31],UH8U(18)[31],UH8V(18)[31],UH9U(18)[31], UH9V(18)[31],UI8U(18)[31],UI8V(18)[31],UI9U(18)[31],UI9V(18)[31],=R10NRC(18)[31],=R1991A(18)[31], =R22ULM(18)[31],=R400N(18)[31],=R70B(18)[31],=R9/EW1TM(18)[31],=R9UAG/N(18)[31],=RA4CQ/9(18)[31], - =RC4W/9(18)[31],=RD0L/9(18)[31],=RK6CG/9(18)[31],=RP65UMF(18)[31],=RP67KM(18)[31],=RP68KM(18)[31], - =RP69KM(18)[31],=RP70KM(18)[31],=RP70NM(18)[31],=RP70UK(18)[31],=RP70ZF(18)[31],=RP71KM(18)[31], - =RP72KM(18)[31],=RP72NM(18)[31],=RP73KM(18)[31],=RP73NZ(18)[31],=RP73ZF(18)[31],=RT22UA(18)[31], - =RT77VV(18)[31],=RW4CG/9(18)[31],=RZ5D/9(18)[31],=UA9JFE/9/P(18)[31],=UE3ATV/9(18)[31], + =RC4W/9(18)[31],=RK6CG/9(18)[31],=RP65UMF(18)[31],=RP67KM(18)[31],=RP68KM(18)[31],=RP69KM(18)[31], + =RP70KM(18)[31],=RP70NM(18)[31],=RP70UK(18)[31],=RP70ZF(18)[31],=RP71KM(18)[31],=RP72KM(18)[31], + =RP72NM(18)[31],=RP73KM(18)[31],=RP73NZ(18)[31],=RP73ZF(18)[31],=RP74KM(18)[31],=RT22UA(18)[31], + =RT77VV(18)[31],=RW4CG/9(18)[31],=UA9JFE/9/P(18)[31],=UA9UAX/M(18)[31],=UE3ATV/9(18)[31], R8W(16),R9W(16),RA8W(16),RA9W(16),RC8W(16),RC9W(16),RD8W(16),RD9W(16),RE8W(16),RE9W(16),RF8W(16), RF9W(16),RG8W(16),RG9W(16),RJ8W(16),RJ9W(16),RK8W(16),RK9W(16),RL8W(16),RL9W(16),RM8W(16), RM9W(16),RN8W(16),RN9W(16),RO8W(16),RO9W(16),RQ8W(16),RQ9W(16),RT8W(16),RT9W(16),RU8W(16), RU9W(16),RV8W(16),RV9W(16),RW8W(16),RW9W(16),RX8W(16),RX9W(16),RY8W(16),RY9W(16),RZ8W(16), RZ9W(16),U8W(16),U9W(16),UA8W(16),UA9W(16),UB8W(16),UB9W(16),UC8W(16),UC9W(16),UD8W(16),UD9W(16), UE8W(16),UE9W(16),UF8W(16),UF9W(16),UG8W(16),UG9W(16),UH8W(16),UH9W(16),UI8W(16),UI9W(16), - =R100W(16),=R100WW(16),=R10RTRS/9(16),=R18KDR/4(16),=R2013CG(16),=R2015AS(16),=R2015DS(16), - =R2015KM(16),=R2017F/P(16),=R20BIS(16),=R20UFA(16),=R25ARCK/4(16),=R25MSB(16),=R25WPW(16), - =R27UFA(16),=R3XX/9(16),=R44WFF(16),=R7378TM(16),=R8JAJ/4(16),=R8JAJ/9(16),=R90WGM(16), - =R90WJV(16),=R90WOB(16),=R90WXK(16),=R9LY/4(16),=RA0R/4(16),=RA1ZPC/9(16),=RA3AUU/9(16), - =RA4POX/9(16),=RA9KDX/8/M(16),=RF9W(16),=RG5A/8(16),=RK3PWJ/9(16),=RK6YYA/9/M(16),=RK9KWI/9(16), - =RK9KWI/9/P(16),=RL3DX/9(16),=RM90WF(16),=RM9RZ/9/P(16),=RN9WWW/9/M(16),=RN9WWW/P(16),=RO17CW(16), - =RP67GI(16),=RP67MG(16),=RP67NG(16),=RP67RK(16),=RP67SW(16),=RP67UF(16),=RP68GM(16),=RP68NK(16), - =RP68UF(16),=RP69GI(16),=RP69PW(16),=RP69UF(16),=RP70GI(16),=RP70GM(16),=RP70LS(16),=RP70NK(16), - =RP70UF(16),=RP70ZO(16),=RP71GI(16),=RP71GM(16),=RP71UF(16),=RP72AR(16),=RP72GI(16),=RP72GM(16), - =RP72UF(16),=RP72WU(16),=RP73AR(16),=RP73GI(16),=RP73UF(16),=RP73WU(16),=RT22WF(16),=RT2F/4(16), - =RT2F/4/M(16),=RT2F/9/M(16),=RT73EA(16),=RT73EL(16),=RT8A/4(16),=RT9W(16),=RT9W/P(16), - =RU110RAEM(16),=RU20WC(16),=RU22WZ(16),=RU27WB(16),=RU27WF(16),=RU27WN(16),=RU27WO(16), - =RU3HD/9/P(16),=RU90WZ(16),=RU9KC/4/M(16),=RU9SO/4(16),=RU9SO/4/P(16),=RV22WB(16),=RV2FZ/9(16), - =RV90WB(16),=RV9CHB/4(16),=RW3SN/9(16),=RW3XX/9(16),=RW4WA/9/P(16),=RW90WC(16),=RW9FWR/9/M(16), - =RW9JZ/4(16),=RW9JZ/9(16),=RX22WN(16),=RZ16WF(16),=RZ90W(16),=RZ90WU(16),=UA0AZA/9(16), - =UA1AAE/9(16),=UA1ZPC/9(16),=UA4LU/9/P(16),=UA4PIE/9(16),=UA4PIE/9/M(16),=UA4PIE/9/P(16), - =UA4PJM/9(16),=UA4PJM/9/M(16),=UA4PJM/9/P(16),=UA4PXR/9/M(16),=UA9KAA/4(16),=UA9KAA/9(16), - =UB5O/4/M(16),=UE10RFF/4(16),=UE90W(16), + =R100W(16),=R10RTRS/9(16),=R18KDR/4(16),=R2013CG(16),=R2015AS(16),=R2015DS(16),=R2015KM(16), + =R2017F/P(16),=R2019CG(16),=R20BIS(16),=R20UFA(16),=R25ARCK/4(16),=R25MSB(16),=R25WPW(16), + =R27UFA(16),=R3XX/9(16),=R44WFF(16),=R53ICGA(16),=R53ICGB(16),=R53ICGC(16),=R53ICGF(16), + =R53ICGJ(16),=R53ICGS(16),=R53ICGV(16),=R53ICGW(16),=R7378TM(16),=R8JAJ/4(16),=R8JAJ/9(16), + =R90WGM(16),=R90WJV(16),=R90WOB(16),=R90WXK(16),=R9LY/4(16),=RA0R/4(16),=RA1ZPC/9(16), + =RA3AUU/9(16),=RA4POX/9(16),=RA9KDX/8/M(16),=RF9W(16),=RG5A/8(16),=RK3PWJ/9(16),=RK6YYA/9/M(16), + =RK9KWI/9(16),=RK9KWI/9/P(16),=RL3DX/9(16),=RM90WF(16),=RM9RZ/9/P(16),=RN9S/M(16),=RN9WWW/9/M(16), + =RN9WWW/P(16),=RO17CW(16),=RP67GI(16),=RP67MG(16),=RP67NG(16),=RP67RK(16),=RP67SW(16),=RP67UF(16), + =RP68GM(16),=RP68NK(16),=RP68UF(16),=RP69GI(16),=RP69PW(16),=RP69UF(16),=RP70GI(16),=RP70GM(16), + =RP70LS(16),=RP70NK(16),=RP70UF(16),=RP70ZO(16),=RP71GI(16),=RP71GM(16),=RP71UF(16),=RP72AR(16), + =RP72GI(16),=RP72GM(16),=RP72UF(16),=RP72WU(16),=RP73AR(16),=RP73GI(16),=RP73UF(16),=RP73WU(16), + =RP74GI(16),=RP74UF(16),=RT22WF(16),=RT2F/4(16),=RT2F/4/M(16),=RT2F/9/M(16),=RT73EA(16), + =RT73EL(16),=RT8A/4(16),=RT9W(16),=RT9W/P(16),=RU110RAEM(16),=RU20WC(16),=RU22WZ(16),=RU27WB(16), + =RU27WF(16),=RU27WN(16),=RU27WO(16),=RU3HD/9/P(16),=RU90WZ(16),=RU9KC/4/M(16),=RU9SO/4(16), + =RU9SO/4/P(16),=RV22WB(16),=RV2FZ/9(16),=RV90WB(16),=RV9CHB/4(16),=RW3SN/9(16),=RW3XX/9(16), + =RW4WA/9/P(16),=RW90WC(16),=RW9FWR/9/M(16),=RW9JZ/4(16),=RW9JZ/9(16),=RW9WJ/P(16),=RX22WN(16), + =RZ16WF(16),=RZ90W(16),=RZ90WU(16),=UA0AZA/9(16),=UA1AAE/9(16),=UA1ZPC/9(16),=UA4LU/9/P(16), + =UA4PIE/9(16),=UA4PIE/9/M(16),=UA4PIE/9/P(16),=UA4PJM/9(16),=UA4PJM/9/M(16),=UA4PJM/9/P(16), + =UA4PXR/9/M(16),=UA9KAA/4(16),=UA9KAA/9(16),=UB5O/4/M(16),=UE10RFF/4(16),=UE90W(16), R8Y(18)[31],R9Y(18)[31],RA8Y(18)[31],RA9Y(18)[31],RC8Y(18)[31],RC9Y(18)[31],RD8Y(18)[31], RD9Y(18)[31],RE8Y(18)[31],RE9Y(18)[31],RF8Y(18)[31],RF9Y(18)[31],RG8Y(18)[31],RG9Y(18)[31], RJ8Y(18)[31],RJ9Y(18)[31],RK8Y(18)[31],RK9Y(18)[31],RL8Y(18)[31],RL9Y(18)[31],RM8Y(18)[31], @@ -2634,10 +2684,10 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: UC9Y(18)[31],UD8Y(18)[31],UD9Y(18)[31],UE8Y(18)[31],UE9Y(18)[31],UF8Y(18)[31],UF9Y(18)[31], UG8Y(18)[31],UG9Y(18)[31],UH8Y(18)[31],UH9Y(18)[31],UI8Y(18)[31],UI9Y(18)[31],=R2015RR(18)[31], =R2015SV(18)[31],=R6XBA/9(18)[31],=R9/UN7JHC(18)[31],=R9/UN7JMO(18)[31],=RA/IK5MIC(18)[31], - =RA/IK5MIC/M(18)[31],=RA0CCJ/9(18)[31],=RA50VT(18)[31],=RK1B/9(18)[31],=RP68BP(18)[31], - =RP68TZ(18)[31],=RP70AF(18)[31],=RP70BP(18)[31],=RP70GA(18)[31],=RP71BP(18)[31],=RP72BP(18)[31], - =RP73BP(18)[31],=RP9Y(18)[31],=RP9YAF(18)[31],=RP9YTZ(18)[31],=RT73GM(18)[31],=RW22WG(18)[31], - =RX6AY/9(18)[31],=UA0LLW/9(18)[31],=UA0ZDY/9(18)[31],=UA9MA/M(18)[31],=UA9UAX/9/P(18)[31], + =RA/IK5MIC/M(18)[31],=RA0CCJ/9(18)[31],=RA50VT(18)[31],=RD0L/9(18)[31],=RK1B/9(18)[31], + =RP68BP(18)[31],=RP68TZ(18)[31],=RP70AF(18)[31],=RP70BP(18)[31],=RP70GA(18)[31],=RP71BP(18)[31], + =RP72BP(18)[31],=RP73BP(18)[31],=RP9Y(18)[31],=RP9YAF(18)[31],=RP9YTZ(18)[31],=RT73GM(18)[31], + =RW22WG(18)[31],=RX6AY/9(18)[31],=UA0LLW/9(18)[31],=UA0ZDY/9(18)[31],=UA9UAX/9/P(18)[31], =UE0ZOO/9(18)[31],=UE44R/9(18)[31],=UE80AL(18)[31], R8Z(18)[31],R9Z(18)[31],RA8Z(18)[31],RA9Z(18)[31],RC8Z(18)[31],RC9Z(18)[31],RD8Z(18)[31], RD9Z(18)[31],RE8Z(18)[31],RE9Z(18)[31],RF8Z(18)[31],RF9Z(18)[31],RG8Z(18)[31],RG9Z(18)[31], @@ -2647,8 +2697,9 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: RW9Z(18)[31],RX8Z(18)[31],RX9Z(18)[31],RY8Z(18)[31],RY9Z(18)[31],RZ8Z(18)[31],RZ9Z(18)[31], U8Z(18)[31],U9Z(18)[31],UA8Z(18)[31],UA9Z(18)[31],UB8Z(18)[31],UB9Z(18)[31],UC8Z(18)[31], UC9Z(18)[31],UD8Z(18)[31],UD9Z(18)[31],UE8Z(18)[31],UE9Z(18)[31],UF8Z(18)[31],UF9Z(18)[31], - UG8Z(18)[31],UG9Z(18)[31],UH8Z(18)[31],UH9Z(18)[31],UI8Z(18)[31],UI9Z(18)[31], - =RA/IK5MIC/P(18)[31],=RC9YA/9/M(18)[31],=RW9MD/9/P(18)[31],=UA0KBG/9/P(18)[31],=UA9MAC/9(18)[31], + UG8Z(18)[31],UG9Z(18)[31],UH8Z(18)[31],UH9Z(18)[31],UI8Z(18)[31],UI9Z(18)[31],=RA/DJ8QP(18)[31], + =RA/IK5MIC/P(18)[31],=RA3DS/P(18)[31],=RC9YA/9/M(18)[31],=RW9MD/9/P(18)[31],=UA0KBG/9/P(18)[31], + =UA3A/P(18)[31],=UA9MAC/9(18)[31], R0A(18)[32],R0B(18)[32],R0H(18)[32],RA0A(18)[32],RA0B(18)[32],RA0H(18)[32],RC0A(18)[32], RC0B(18)[32],RC0H(18)[32],RD0A(18)[32],RD0B(18)[32],RD0H(18)[32],RE0A(18)[32],RE0B(18)[32], RE0H(18)[32],RF0A(18)[32],RF0B(18)[32],RF0H(18)[32],RG0A(18)[32],RG0B(18)[32],RG0H(18)[32], @@ -2667,18 +2718,18 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: =R44YETI/9(18)[32],=R50CQM(18)[32],=R63RRC(18)[32],=R7LZ/9(18)[32],=RA/UR5HVR(18)[32], =RA0/UR5HVR(18)[32],=RA1AMW/0(18)[32],=RA3AUU/0(18)[32],=RA3BB/0(18)[32],=RA3DA/0(18)[32], =RA3DA/9(18)[32],=RA4CQ/0(18)[32],=RA4CSX/0(18)[32],=RA4RU/0(18)[32],=RA9UT/0(18)[32], - =RAEM(18)[32],=RD110RAEM(18)[32],=RI0BV/0(18)[32],=RK3DZJ/9(18)[32],=RK56GC(18)[32], + =RAEM(18)[32],=RD110RAEM(18)[32],=RI0B(18)[32],=RI0BV/0(18)[32],=RK3DZJ/9(18)[32],=RK56GC(18)[32], =RK6BBM/9(18)[32],=RK80KEDR(18)[32],=RL5G/9(18)[32],=RM0A(18)[32],=RM2D/9(18)[32], =RM9RZ/0(18)[32],=RN0A(18)[32],=RN110RAEM(18)[32],=RN110RAEM/P(18)[32],=RP70KV(18)[32], - =RP70RS(18)[32],=RP73KT(18)[32],=RT22SA(18)[32],=RT9K/9(18)[32],=RU19NY(18)[32],=RU3FF/0(18)[32], - =RU4CO/0(18)[32],=RV3DHC/0(18)[32],=RV3DHC/0/P(18)[32],=RV9WP/9(18)[32],=RW3XN/0(18)[32], - =RW3YC/0(18)[32],=RW3YC/9(18)[32],=RY1AAB/9(18)[32],=RY1AAB/9/M(18)[32],=RZ3DSA/0(18)[32], - =RZ3DZS/0(18)[32],=RZ9ON/9(18)[32],=UA0ACG/0(18)[32],=UA0FCB/0(18)[32],=UA0FCB/0/P(18)[32], - =UA0WG/0(18)[32],=UA0WW/0(18)[32],=UA0WW/M(18)[32],=UA0WY/0(18)[32],=UA3ADN/0(18)[32], - =UA4LU/0(18)[32],=UA4PT/0(18)[32],=UA6BTN/0(18)[32],=UA9UAX/9(18)[32],=UA9WDK/0(18)[32], - =UB1AJQ/0(18)[32],=UE1WFF/0(18)[32], - =R100D(18)[22],=R100DI(18)[22],=R3CA/9(18)[22],=RA3XR/0(18)[22],=RA9LI/0(18)[22],=RI0B(18)[22], - =RI0BDI(18)[22],=RS0B(18)[22],=RS0B/P(18)[22],=RV3EFH/0(18)[22],=RW1AI/9(18)[22],=RW3GW/0(18)[22], + =RP70RS(18)[32],=RP73KT(18)[32],=RP74KT(18)[32],=RT22SA(18)[32],=RT9K/9(18)[32],=RU19NY(18)[32], + =RU3FF/0(18)[32],=RU4CO/0(18)[32],=RV3DHC/0(18)[32],=RV3DHC/0/P(18)[32],=RV9WP/9(18)[32], + =RW3XN/0(18)[32],=RW3YC/0(18)[32],=RW3YC/9(18)[32],=RY1AAB/9(18)[32],=RY1AAB/9/M(18)[32], + =RZ3DSA/0(18)[32],=RZ3DZS/0(18)[32],=RZ9ON/9(18)[32],=UA0ACG/0(18)[32],=UA0FCB/0(18)[32], + =UA0FCB/0/P(18)[32],=UA0WG/0(18)[32],=UA0WW/0(18)[32],=UA0WW/M(18)[32],=UA0WY/0(18)[32], + =UA3ADN/0(18)[32],=UA4LU/0(18)[32],=UA4PT/0(18)[32],=UA6BTN/0(18)[32],=UA9UAX/9(18)[32], + =UA9WDK/0(18)[32],=UB1AJQ/0(18)[32],=UE1WFF/0(18)[32], + =R100D(18)[22],=R100DI(18)[22],=R3CA/9(18)[22],=RA3XR/0(18)[22],=RA9LI/0(18)[22],=RI0BDI(18)[22], + =RS0B(18)[22],=RS0B/P(18)[22],=RV3EFH/0(18)[22],=RW1AI/9(18)[22],=RW3GW/0(18)[22], =RX6LMQ/0(18)[22],=RZ9DX/0(18)[22],=RZ9DX/0/A(18)[22],=RZ9DX/0/P(18)[22],=RZ9DX/9(18)[22], =RZ9DX/9/P(18)[22],=RZ9OO/0(18)[22],=UA1ADQ/0(18)[22],=UA3HY/0(18)[22],=UA3YH/0(18)[22], =UA4RX/0(18)[22],=UA9FL/0(18)[22],=UE0BFF(18)[22],=UE44POL(18)[22],=UE44POL/P(18)[22], @@ -2706,11 +2757,12 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: RZ0F(19)[34],U0E(19)[34],U0F(19)[34],UA0E(19)[34],UA0F(19)[34],UB0E(19)[34],UB0F(19)[34], UC0E(19)[34],UC0F(19)[34],UD0E(19)[34],UD0F(19)[34],UE0E(19)[34],UE0F(19)[34],UF0E(19)[34], UF0F(19)[34],UG0E(19)[34],UG0F(19)[34],UH0E(19)[34],UH0F(19)[34],UI0E(19)[34],UI0F(19)[34], - =R10RLHA/0(19)[34],=R7AA/0(19)[34],=R7LP/0(19)[34],=R7MR/0(19)[34],=RA/KE5JA(19)[34], - =RA/OG2K(19)[34],=RA0SS/0(19)[34],=RA1ALA/0(19)[34],=RA4HKM/0(19)[34],=RA4HKM/0/P(19)[34], - =RA6ABC/0(19)[34],=RM0F(19)[34],=RN0F(19)[34],=RN1CR/0(19)[34],=RS0F(19)[34],=RT6A/0(19)[34], - =RV1CC/0(19)[34],=RZ3DW/0(19)[34],=RZ4HD/0(19)[34],=RZ55YG(19)[34],=RZ9ODD/0(19)[34], - =RZ9OWE/0(19)[34],=UA1ANA/0(19)[34],=UA3EDP/0(19)[34],=UB40FSU(19)[34],=UE1AAA/0(19)[34], + =R10RLHA/0(19)[34],=R26RRC(19)[34],=R7AA/0(19)[34],=R7LP/0(19)[34],=R7MR/0(19)[34], + =RA/KE5JA(19)[34],=RA/OG2K(19)[34],=RA0SS/0(19)[34],=RA1ALA/0(19)[34],=RA4HKM/0(19)[34], + =RA4HKM/0/P(19)[34],=RA6ABC/0(19)[34],=RM0F(19)[34],=RN0F(19)[34],=RN1CR/0(19)[34],=RS0F(19)[34], + =RT6A/0(19)[34],=RV1CC/0(19)[34],=RZ3DW/0(19)[34],=RZ4HD/0(19)[34],=RZ55YG(19)[34], + =RZ9ODD/0(19)[34],=RZ9OWE/0(19)[34],=UA1ANA/0(19)[34],=UA3EDP/0(19)[34],=UB40FSU(19)[34], + =UE1AAA/0(19)[34], =RV9WP/0(18)[22],=U0H/UA0AGQ(18)[22], R0I(19)[24],RA0I(19)[24],RC0I(19)[24],RD0I(19)[24],RE0I(19)[24],RF0I(19)[24],RG0I(19)[24], RI0I(19)[24],RJ0I(19)[24],RK0I(19)[24],RL0I(19)[24],RM0I(19)[24],RN0I(19)[24],RO0I(19)[24], @@ -2743,12 +2795,13 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: UF0N(19)[34],UG0L(19)[34],UG0M(19)[34],UG0N(19)[34],UH0L(19)[34],UH0M(19)[34],UH0N(19)[34], UI0L(19)[34],UI0M(19)[34],UI0N(19)[34],=R0HQ(19)[34],=R150L(19)[34],=R17CWH(19)[34], =R20RRC/0(19)[34],=R3BY/0(19)[34],=R3HD/0(19)[34],=R66IOTA(19)[34],=R70LWA(19)[34], - =R8CW/0(19)[34],=R8XW/0(19)[34],=R9XT/0(19)[34],=RA/IK7YTT(19)[34],=RC/N6TCZ(19)[34], - =RD3BN/0(19)[34],=RL5G/0/P(19)[34],=RM0M(19)[34],=RM5M/0(19)[34],=RN1NS/0(19)[34],=RP0L(19)[34], - =RP0LPK(19)[34],=RP60P(19)[34],=RP66V(19)[34],=RP67SD(19)[34],=RP67V(19)[34],=RP68SD(19)[34], - =RP68V(19)[34],=RP69SD(19)[34],=RP69V(19)[34],=RP70DG(19)[34],=RP70SD(19)[34],=RP70V(19)[34], - =RP71DG(19)[34],=RP71SD(19)[34],=RP71V(19)[34],=RP72DG(19)[34],=RP72SD(19)[34],=RP72V(19)[34], - =RP73DG(19)[34],=RP73SD(19)[34],=RP73V(19)[34],=RU3BY/0(19)[34],=RU5D/0(19)[34],=RV1AW/0(19)[34], + =R8CW/0(19)[34],=R8XW/0(19)[34],=R9XT/0(19)[34],=RA/IK7YTT(19)[34],=RA/OK1DWF(19)[34], + =RC/N6TCZ(19)[34],=RD3BN/0(19)[34],=RL5G/0/P(19)[34],=RM0M(19)[34],=RM5M/0(19)[34], + =RN1NS/0(19)[34],=RP0L(19)[34],=RP0LPK(19)[34],=RP60P(19)[34],=RP66V(19)[34],=RP67SD(19)[34], + =RP67V(19)[34],=RP68SD(19)[34],=RP68V(19)[34],=RP69SD(19)[34],=RP69V(19)[34],=RP70DG(19)[34], + =RP70SD(19)[34],=RP70V(19)[34],=RP71DG(19)[34],=RP71SD(19)[34],=RP71V(19)[34],=RP72DG(19)[34], + =RP72SD(19)[34],=RP72V(19)[34],=RP73DG(19)[34],=RP73SD(19)[34],=RP73V(19)[34],=RP74DG(19)[34], + =RP74SD(19)[34],=RP74V(19)[34],=RU3BY/0(19)[34],=RU5D/0(19)[34],=RV1AW/0(19)[34], =RV3DSA/0(19)[34],=RW22GO(19)[34],=RW3LG/0(19)[34],=RX15RX(19)[34],=UA0SDX/0(19)[34], =UA0SIK/0(19)[34],=UA3AHA/0(19)[34],=UA4SBZ/0(19)[34],=UA6MF/0(19)[34],=UA7R/0(19)[34], =UB0LAP/P(19)[34],=UC0LAF/P(19)[34],=UE1RFF/0(19)[34],=UE70MA(19)[34],=UE75L(19)[34], @@ -2789,7 +2842,7 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: =RA0SP/RP(18)[32],=RA0SR/RP(18)[32],=RA110RAEM(18)[32],=RA3TO/0(18)[32],=RA4CSX/0/P(18)[32], =RA9JG/0(18)[32],=RA9JG/0/P(18)[32],=RA9OBG/0(18)[32],=RA9USU/8(18)[32],=RD0L/0(18)[32], =RK17CW(18)[32],=RK9MZZ/0(18)[32],=RN4HIT/0(18)[32],=RP0S(18)[32],=RP0SXR(18)[32],=RP0SZZ(18)[32], - =RP67ST(18)[32],=RP70AB(18)[32],=RP72AB(18)[32],=RP73AB(18)[32],=RQ0C/9(18)[32], + =RP67ST(18)[32],=RP70AB(18)[32],=RP72AB(18)[32],=RP73AB(18)[32],=RP74AB(18)[32],=RQ0C/9(18)[32], =RV3ACA/0/M(18)[32],=RV6AJ/0(18)[32],=RV7AD/0(18)[32],=RV9JD/0(18)[32],=RW4YA/0(18)[32], =RW4YA/9(18)[32],=RX3AT/0(18)[32],=RX3DFH/0(18)[32],=RX9WN/0(18)[32],=RX9WN/0/M(18)[32], =RX9WN/0/P(18)[32],=RZ0SO/P(18)[32],=UA0KBG/0(18)[32],=UA0KBG/9(18)[32],=UA3EDQ/0(18)[32], @@ -2802,17 +2855,18 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: U0W(18)[31],UA0W(18)[31],UB0W(18)[31],UC0W(18)[31],UD0W(18)[31],UE0W(18)[31],UF0W(18)[31], UG0W(18)[31],UH0W(18)[31],UI0W(18)[31],=R01DTV/9(18)[31],=R10RTRS/0(18)[31],=RA0AM/0(18)[31], =RP0W(18)[31],=RP0W/P(18)[31],=RP0WWS(18)[31],=RP70SL(18)[31],=RP72SL(18)[31],=RV0AE/0/FF(18)[31], - =RZ0AM/0(18)[31],=RZ22WW(18)[31],=UA0FCB/P(18)[31],=UA9UAX/0/M(18)[31],=UB5O/9(18)[31], - =UE0ARD/0(18)[31],=UE10RFF/9(18)[31],=UE1RFF/0/P(18)[31],=UE9FDA/0(18)[31],=UE9FDA/0/M(18)[31], - =R23RRC(19)[25],=UA6HMC/0(19)[25], + =RZ0AM/0(18)[31],=RZ22WW(18)[31],=RZ5D/9(18)[31],=UA0FCB/P(18)[31],=UA9UAX/0/M(18)[31], + =UB5O/9(18)[31],=UE0ARD/0(18)[31],=UE10RFF/9(18)[31],=UE1RFF/0/P(18)[31],=UE9FDA/0(18)[31], + =UE9FDA/0/M(18)[31], + =R205NEW(19)[25],=R23RRC(19)[25],=UA6HMC/0(19)[25], R0Y(23)[32],RA0Y(23)[32],RC0Y(23)[32],RD0Y(23)[32],RE0Y(23)[32],RF0Y(23)[32],RG0Y(23)[32], RJ0Y(23)[32],RK0Y(23)[32],RL0Y(23)[32],RM0Y(23)[32],RN0Y(23)[32],RO0Y(23)[32],RQ0Y(23)[32], RT0Y(23)[32],RU0Y(23)[32],RV0Y(23)[32],RW0Y(23)[32],RX0Y(23)[32],RY0Y(23)[32],RZ0Y(23)[32], U0Y(23)[32],UA0Y(23)[32],UB0Y(23)[32],UC0Y(23)[32],UD0Y(23)[32],UE0Y(23)[32],UF0Y(23)[32], - UG0Y(23)[32],UH0Y(23)[32],UI0Y(23)[32],=R3YAB/9/P(23)[32],=R9OOO/9/M(23)[32],=R9OOO/9/P(23)[32], - =R9OY/9/P(23)[32],=RA0AJ/0/P(23)[32],=RA0WA/0/P(23)[32],=RA9YME/0(23)[32],=RK3BY/0(23)[32], - =RP0Y(23)[32],=RX0AE/0(23)[32],=RX0AT/0/P(23)[32],=UA0ADU/0(23)[32],=UA0WGD/0(23)[32], - =UA9ZZ/0/P(23)[32],=UE0OFF/0(23)[32],=UE44Y/9(23)[32],=UE70Y(23)[32], + UG0Y(23)[32],UH0Y(23)[32],UI0Y(23)[32],=R0WX/P(23)[32],=R3YAB/9/P(23)[32],=R9OOO/9/M(23)[32], + =R9OOO/9/P(23)[32],=R9OY/9/P(23)[32],=RA0AJ/0/P(23)[32],=RA0WA/0/P(23)[32],=RA9YME/0(23)[32], + =RK3BY/0(23)[32],=RP0Y(23)[32],=RX0AE/0(23)[32],=RX0AT/0/P(23)[32],=UA0ADU/0(23)[32], + =UA0WGD/0(23)[32],=UA9ZZ/0/P(23)[32],=UE0OFF/0(23)[32],=UE44Y/9(23)[32],=UE70Y(23)[32], R0X(19)[35],R0Z(19)[35],RA0X(19)[35],RA0Z(19)[35],RC0X(19)[35],RC0Z(19)[35],RD0X(19)[35], RD0Z(19)[35],RE0X(19)[35],RE0Z(19)[35],RF0X(19)[35],RF0Z(19)[35],RG0X(19)[35],RG0Z(19)[35], RI0X(19)[35],RI0Z(19)[35],RJ0X(19)[35],RJ0Z(19)[35],RK0X(19)[35],RK0Z(19)[35],RL0X(19)[35], @@ -2840,8 +2894,7 @@ Asiatic Russia: 17: 30: AS: 55.88: -84.08: -7.0: UA9: =R7AB/9(18)[32],=RA/UR5WT(18)[32],=RA77VV(18)[32],=RB110RAEM(18)[32],=RK0AXC/0(18)[32], =RK0AXC/0/M(18)[32],=RK6YYA/0(18)[32],=RK6YYA/0/M(18)[32],=RN4CU/0(18)[32],=RN4CU/0/P(18)[32], =RN9A/0(18)[32],=RP0UWZ(18)[32],=RP0UZF(18)[32],=RW0UM/0(18)[32],=RZ19NY(18)[32], - =UA3AKO/0/M(18)[32],=UE15UWC(18)[32],=UE23DZO(18)[32],=UE70UVV(18)[32],=UE70UWW(18)[32], - =UE75VV(18)[32]; + =UA3AKO/0/M(18)[32],=UE15UWC(18)[32],=UE70UVV(18)[32],=UE70UWW(18)[32],=UE75VV(18)[32]; Uzbekistan: 17: 30: AS: 41.40: -63.97: -5.0: UK: UJ,UK,UL,UM,=U8AG,=U8AH,=U8AI,=UK/DF3DS/Z; Kazakhstan: 17: 30: AS: 48.17: -65.18: -5.0: UN: @@ -2898,12 +2951,12 @@ Marshall Islands: 31: 65: OC: 9.08: -167.33: -12.0: V7: Brunei Darussalam: 28: 54: OC: 4.50: -114.60: -8.0: V8: V8; Canada: 05: 09: NA: 44.35: 78.75: 5.0: VE: - CF,CG,CJ,CK,VA,VB,VC,VE,VG,VX,VY9,XL,XM,=VE2EM/M,=VER20190212, + CF,CG,CJ,CK,VA,VB,VC,VE,VG,VX,VY9,XL,XM,=VE2EM/M,=VER20190630, =CF7AAW/1,=CK7IG/1,=VA3QSL/1,=VA3WR/1,=VE1REC/LH,=VE1REC/M/LH,=VE3RSA/1,=VE7IG/1, CF2[4],CG2[4],CJ2[4],CK2[4],VA2[4],VB2[4],VC2[4],VE2[4],VG2[4],VX2[4],XL2[4],XM2[4],=4Y1CAO[4], - =CY2ZT/2[4],=VA3ELE/2[4],=VA3MPM/2[4],=VA7AQ/P[4],=VE2/G3ZAY/P[4],=VE2/M0BLF/P[4],=VE2FK[9], - =VE2HAY/P[4],=VE2MAM/P[4],=VE2OV/P[4],=VE3AP/2[4],=VE3EXY/2[4],=VE3GF/2[4],=VE3GNO/2[4], - =VE3IAC/2[4],=VE3ZZ/2[4],=VE6TC/2[4],=VE7IG/2[4],=XO0ICE/2[4], + =CY2ZT/2[4],=VA3MPM/2[4],=VA7AQ/P[4],=VE2/G3ZAY/P[4],=VE2/M0BLF/P[4],=VE2FK[9],=VE2HAY/P[4], + =VE2MAM/P[4],=VE2OV/P[4],=VE3AP/2[4],=VE3EXY/2[4],=VE3GF/2[4],=VE3GNO/2[4],=VE3IAC/2[4], + =VE3ZZ/2[4],=VE6TC/2[4],=VE7IG/2[4],=XO0ICE/2[4], CF3(4)[4],CG3(4)[4],CJ3(4)[4],CK3(4)[4],VA3(4)[4],VB3(4)[4],VC3(4)[4],VE3(4)[4],VG3(4)[4], VX3(4)[4],XL3(4)[4],XM3(4)[4],=CF7EWK/3(4)[4],=CI0XN/P(4)[4],=CJ7EWK/3(4)[4],=VA7EWK/3(4)[4], =VE1RM/3(4)[4],=VE2AEJ/3(4)[4],=VE2MAM/3(4)[4],=VE2PK/3(4)[4],=VE2QLF/3(4)[4],=VE2QV/3(4)[4], @@ -2932,24 +2985,25 @@ Canada: 05: 09: NA: 44.35: 78.75: 5.0: VE: CI2,CZ2,VF2,VY2,XK2,XO2, =CF2RC(2)[4],=CF2VVV(2)[4],=CJ2BY(2)[4],=CJ2KCE(2)[4],=K3FMQ/VE2(2)[4],=K5YG/VE2(2)[4], =KD3RF/VE2(2)[4],=KD3TB/VE2(2)[4],=N5ZO/VE2(2)[4],=VA1CN/2(2)[4],=VA2BK(2)[4],=VA2BY(2)[4], - =VA2KCE(2)[4],=VA2MCJ/VE2(2)[4],=VA2RAG(2)[4],=VA2RC(2)[4],=VA2VFT(2)[4],=VA2VVV(2)[4], - =VA3NA/2(2)[4],=VB2C(2)[4],=VB2R(2)[4],=VB2T(2)[4],=VB2V(2)[4],=VB2W(2)[4],=VC2C(2)[4], - =VC2EME(2)[4],=VC2Q(2)[4],=VC2R(2)[4],=VC2X(2)[4],=VC3W/2(2)[4],=VE2/JA8BMK(2)[4],=VE2/K5YG(2)[4], - =VE2/KD3RF(2)[4],=VE2/KD3RF/M(2)[4],=VE2/N1NK(2)[4],=VE2/UT3UA(2)[4],=VE2/W2NTJ(2)[4], - =VE2/W5GED(2)[4],=VE2A(2)[4],=VE2ACP/P(2)[4],=VE2AE(2)[4],=VE2CSI(2)[4],=VE2CVI(2)[4], - =VE2DXY(2)[4],=VE2EKA(2)[4],=VE2EW(2)[4],=VE2FDJ/2(2)[4],=VE2GHZ/2(2)[4],=VE2HRI(2)[4], - =VE2IDX(2)[4],=VE2III(2)[4],=VE2IM(2)[4],=VE2KK(2)[4],=VE2NN(2)[4],=VE2OTT(2)[4],=VE2PR(2)[4], - =VE2PRG(2)[4],=VE2QIP/2(2)[4],=VE2WDX(2)[4],=VE2XAA/2(2)[4],=VE2XB/2(2)[4],=VE2Z(2)[4], - =VE3AXC/2(2)[4],=VE3CWU/2(2)[4],=VE3EXY/VE2(2)[4],=VE3EY/2(2)[4],=VE3FDX/2(2)[4],=VE3JM/2(2)[4], - =VE3NE/2(2)[4],=VE3NWA/2(2)[4],=VE3RHJ/2(2)[4],=VE3ZF/2(2)[4],=VE7ACN/2(2)[4],=VE7ACN/VE2(2)[4], - =VE7MID/VE2(2)[4],=VE8DX/2(2)[4],=W0SD/VE2(2)[4],=W2NTJ/VE2(2)[4],=W4TMO/VE2(2)[4], - =W5GED/VE2(2)[4],=WB8YTZ/VE2(2)[4],=XM3NE/2(2)[4], + =VA2KCE(2)[4],=VA2MCJ/VE2(2)[4],=VA2RAG(2)[4],=VA2VFT(2)[4],=VA2VVV(2)[4],=VA3ELE/2(2)[4], + =VA3NA/2(2)[4],=VA7XW/VE2(2)[4],=VB2C(2)[4],=VB2R(2)[4],=VB2T(2)[4],=VB2V(2)[4],=VB2W(2)[4], + =VC2C(2)[4],=VC2EME(2)[4],=VC2Q(2)[4],=VC2R(2)[4],=VC2X(2)[4],=VC3W/2(2)[4],=VE2/JA8BMK(2)[4], + =VE2/K5YG(2)[4],=VE2/KD3RF(2)[4],=VE2/KD3RF/M(2)[4],=VE2/N1NK(2)[4],=VE2/UT3UA(2)[4], + =VE2/W2NTJ(2)[4],=VE2/W5GED(2)[4],=VE2A(2)[4],=VE2ACP/P(2)[4],=VE2AE(2)[4],=VE2CSI(2)[4], + =VE2CVI(2)[4],=VE2DXY(2)[4],=VE2EKA(2)[4],=VE2FDJ/2(2)[4],=VE2GHZ/2(2)[4],=VE2HRI(2)[4], + =VE2IDX(2)[4],=VE2III(2)[4],=VE2IM(2)[4],=VE2KK(2)[4],=VE2NN(2)[4],=VE2OTT(2)[4],=VE2PRG(2)[4], + =VE2QIP/2(2)[4],=VE2TKH(2)[4],=VE2TWO(2)[4],=VE2WDX(2)[4],=VE2XAA/2(2)[4],=VE2XB/2(2)[4], + =VE2Z(2)[4],=VE3AXC/2(2)[4],=VE3CWU/2(2)[4],=VE3EY/2(2)[4],=VE3FDX/2(2)[4],=VE3JM/2(2)[4], + =VE3NE/2(2)[4],=VE3NWA/2(2)[4],=VE3RHJ/2(2)[4],=VE3ZF/2(2)[4],=VE7ACN/VE2(2)[4],=VE7MID/VE2(2)[4], + =VE8DX/2(2)[4],=W0SD/VE2(2)[4],=W2NTJ/VE2(2)[4],=W4TMO/VE2(2)[4],=W5GED/VE2(2)[4], + =WB8YTZ/VE2(2)[4],=XM3NE/2(2)[4], =K8JJ/VY0(4)[4],=K9AJ/VY0(4)[4],=KD6WW/VY0(4)[4],=VY0A(4)[4],=VY0V(4)[4]; Australia: 30: 59: OC: -23.70: -132.33: -10.0: VK: AX,VH,VI,VJ,VK,VL,VM,VN,VZ,=VK9MAV, - =AX2000/IMD,=AX2000/LH,=VI90IARU,=VK6AV/2,=VK6AXB/2,=VK6DXI/2,=VK6MB/2,=VK6YB/2,=VK6ZOA/2, + =VK6MB/1, + =AX2000/IMD,=AX2000/LH,=VI90IARU,=VK4VXX,=VK6AV/2,=VK6AXB/2,=VK6DXI/2,=VK6MB/2,=VK6YB/2,=VK6ZOA/2, =VK8GMT/2,=VK9LX/2, - =AX8AA,=VK3DK/LH,=VK6FMON/3,=VK6JON/3,=VK6NX/3,=VK6SX/3,=VK9LA/3,=VK9ZLH/3, + =AX8AA,=VK3DK/LH,=VK6FMON/3,=VK6JON/3,=VK6MB/3,=VK6NX/3,=VK6SX/3,=VK9LA/3,=VK9ZLH/3, AX4[55],VH4[55],VI4[55],VJ4[55],VK4[55],VL4[55],VM4[55],VN4[55],VZ4[55],=VK100WIA[55], =VK4MM/LH[55],=VK4WIA/HQ[55],=VK5MAV/9[55],=VK6AV/4[55],=VK6CN/4[55],=VK6DW/4[55],=VK6DXI/4[55], =VK6JON/4[55],=VK6KM/4[55],=VK6LC/4[55],=VK6NAI/4[55],=VK6ZN/4[55],=VK8FUNN/4[55],=VK8GM/4[55], @@ -2961,9 +3015,9 @@ Australia: 30: 59: OC: -23.70: -132.33: -10.0: VK: =VK2IA/6(29)[58],=VK2RAS/6(29)[58],=VK3DP/6(29)[58],=VK3DXI/6(29)[58],=VK3FPF/6(29)[58], =VK3FPIL/6(29)[58],=VK3JBL/6(29)[58],=VK3KG/6(29)[58],=VK3MCD/6(29)[58],=VK3NUT/6(29)[58], =VK3OHM/6(29)[58],=VK3TWO/6(29)[58],=VK3YQS/6(29)[58],=VK4IXU/6(29)[58],=VK4JWG/6(29)[58], - =VK4NAI/6(29)[58],=VK4NH/6(29)[58],=VK4SN/6(29)[58],=VK4VXX(29)[58],=VK4VXX/6(29)[58], - =VK5CC/6(29)[58],=VK5CE/6(29)[58],=VK5CE/9(29)[58],=VK5MAV/6(29)[58],=VK5NHG/6(29)[58], - =VK5PAS/6(29)[58],=VK6BV/AF(29)[58],=VK9AR(29)[58],=VK9AR/6(29)[58],=VK9ZLH/6(29)[58], + =VK4NAI/6(29)[58],=VK4NH/6(29)[58],=VK4SN/6(29)[58],=VK4VXX/6(29)[58],=VK5CC/6(29)[58], + =VK5CE/6(29)[58],=VK5CE/9(29)[58],=VK5MAV/6(29)[58],=VK5NHG/6(29)[58],=VK5PAS/6(29)[58], + =VK6BV/AF(29)[58],=VK9AR(29)[58],=VK9AR/6(29)[58],=VK9ZLH/6(29)[58], =VK6JON/7,=VK6KSJ/7,=VK6ZN/7,=VK7NWT/LH,=VK8XX/7, AX8(29)[55],VH8(29)[55],VI8(29)[55],VJ8(29)[55],VK8(29)[55],VL8(29)[55],VM8(29)[55],VN8(29)[55], VZ8(29)[55],=VI5RAS/8(29)[55],=VK1AHS/8(29)[55],=VK1FOC/8(29)[55],=VK2CBD/8(29)[55], @@ -3009,7 +3063,7 @@ Ducie Island: 32: 63: OC: -24.70: 124.80: 8.0: VP6/d: Falkland Islands: 13: 16: SA: -51.63: 58.72: 4.0: VP8: VP8; South Georgia Island: 13: 73: SA: -54.48: 37.08: 2.0: VP8/g: - =VP8CA,=VP8CKB,=VP8DIF,=VP8DKX,=VP8DOZ,=VP8DXU,=VP8GEO,=VP8GI,=VP8SGB,=VP8SGI,=VP8SGK; + =VP8CA,=VP8CKB,=VP8DIF,=VP8DKX,=VP8DOZ,=VP8GEO,=VP8GI,=VP8SGB,=VP8SGI,=VP8SGK; South Shetland Islands: 13: 73: SA: -62.08: 58.67: 4.0: VP8/h: CE9,XR9,=BY/R1ANF,=CA8WCI/9,=CV0A,=D88S,=DP1ANF,=DT8A,=EA/FT5YK,=EA/FT5YK/P,=EA1CYK/P,=EA1CYK/VP8, =EA4FZR,=EA4FZR/P,=ED3RKL,=HC/FT5YK,=HF0/R1ANF,=HF0APAS,=HF0ARC,=HF0POL,=HF0POL/LH,=HF0QF,=HL0KSJ, @@ -3092,7 +3146,7 @@ Aves Island: 08: 11: NA: 15.67: 63.60: 4.0: YV0: 4M0,YV0,YW0,YX0,YY0; Zimbabwe: 38: 53: AF: -18.00: -31.00: -2.0: Z2: Z2,=Z21KD/L,=Z27JAM/J; -Macedonia: 15: 28: EU: 41.60: -21.65: -1.0: Z3: +North Macedonia: 15: 28: EU: 41.60: -21.65: -1.0: Z3: Z3; Republic of Kosovo: 15: 28: EU: 42.67: -21.17: -1.0: Z6: Z6; @@ -3126,7 +3180,7 @@ Kermadec Islands: 32: 60: OC: -29.25: 177.92: -12.0: ZL8: N.Z. Subantarctic Is.: 32: 60: OC: -51.62: -167.62: -12.0: ZL9: ZL9; Paraguay: 11: 14: SA: -25.27: 57.67: 4.0: ZP: - ZP; + ZP,=VERSION; South Africa: 38: 57: AF: -29.07: -22.63: -2.0: ZS: H5,S4,S8,V9,ZR,ZS,ZT,ZU,=ZS70BAK/L,=ZS71SIG,=ZS75PTA,=ZS85SARL, =ZS1BAK/L,=ZS1CT/L,=ZS1CT/LH,=ZS1ESC/L,=ZS1ESC/LH,=ZS1FRC/L,=ZS1FRC/LH,=ZS1OAK/LH,=ZS1OAR/LH, diff --git a/decodedtext.cpp b/decodedtext.cpp index 88f6bd621..bfa808173 100644 --- a/decodedtext.cpp +++ b/decodedtext.cpp @@ -51,11 +51,12 @@ DecodedText::DecodedText (QString const& the_string) QStringList DecodedText::messageWords () const { - if (is_standard_) - { - // extract up to the first four message words - return words_re.match (message_).capturedTexts (); - } + if(is_standard_) { + // extract up to the first four message words + QString t=message_; + if(t.left(4)=="TU; ") t=message_.mid(4,-1); + return words_re.match(t).capturedTexts(); + } // simple word split for free text messages auto words = message_.split (' ', QString::SkipEmptyParts); // add whole message as item 0 to mimic RE capture list diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index e81160575..bc333dd8c 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -52,6 +52,7 @@ set (UG_SRCS tutorial-example1.adoc tutorial-example2.adoc tutorial-example3.adoc + tutorial-example4.adoc tutorial-main-window.adoc tutorial-wide-graph-settings.adoc utilities.adoc @@ -77,6 +78,8 @@ set (UG_IMGS images/FreqCal_Graph.png images/FreqCal_Results.png images/freemsg.png + images/ft4_decodes.png + images/ft4_waterfall.png images/ft8_decodes.png images/FT8_waterfall.png images/help-menu.png diff --git a/doc/common/links.adoc b/doc/common/links.adoc index b81743fc4..58ad60476 100644 --- a/doc/common/links.adoc +++ b/doc/common/links.adoc @@ -91,7 +91,8 @@ d). Edit lines as needed. Keeping them in alphabetic order help see dupes. :sourceforge-jtsdk: https://sourceforge.net/projects/jtsdk[SourceForge JTSDK] :ubuntu_sdk: https://launchpad.net/~ubuntu-sdk-team/+archive/ppa[Ubuntu SDK Notice] :win_openssl_packages: https://slproweb.com/products/Win32OpenSSL.html[Windows OpenSSL Packages] -:win32_openssl: https://slproweb.com/download/Win32OpenSSL_Light-1_0_2q.exe[Win32 OpenSSL Lite Package] +:win32_openssl: https://slproweb.com/download/Win32OpenSSL_Light-1_0_2r.exe[Win32 OpenSSL Lite Package] +:win64_openssl: https://slproweb.com/download/Win64OpenSSL_Light-1_0_2r.exe[Win64 OpenSSL Lite Package] :writelog: https://writelog.com/[Writelog] :wsjt_yahoo_group: https://groups.yahoo.com/neo/groups/wsjtgroup/info[WSJT Group] :wsjtx: http://physics.princeton.edu/pulsar/K1JT/wsjtx.html[WSJT-X] @@ -115,6 +116,7 @@ d). Edit lines as needed. Keeping them in alphabetic order help see dupes. :QRA64_EME: http://physics.princeton.edu/pulsar/K1JT/QRA64_EME.pdf[QRA64 for microwave EME] :svn: http://subversion.apache.org/packages.html#windows[Subversion] :win32: http://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-win32.exe[wsjtx-{VERSION}-win32.exe] +:win64: http://physics.princeton.edu/pulsar/K1JT/wsjtx-{VERSION}-win64.exe[wsjtx-{VERSION}-win64.exe] :wsjt-devel: https://lists.sourceforge.net/lists/listinfo/wsjt-devel[here] :wsjt_repo: https://sourceforge.net/p/wsjt/wsjt_orig/ci/master/tree/[WSJT Source Repository] :wspr_code: http://physics.princeton.edu/pulsar/K1JT/WSPRcode.exe[WSPRcode.exe] diff --git a/doc/user_guide/en/faq.adoc b/doc/user_guide/en/faq.adoc index 9240f3436..27751a493 100644 --- a/doc/user_guide/en/faq.adoc +++ b/doc/user_guide/en/faq.adoc @@ -95,3 +95,19 @@ QT_QPA_PLATFORMTHEME set to empty (the space after the '=' character is necessary): QT_QPA_PLATFORMTHEME= wsjtx + +I am running _WSJT-X_ on Linux using a KDE desktop. Why does *Menu->Configurations* misbehave?:: + +The KDE development team have added code to Qt that tries to +automatically add shortcut accelerator keys to all buttons including +pop up menu buttons, this interferes with operation of the application +(many other Qt applications have similar issues with KDE). Until this +is fixed by the KDE team you must disable this misfeature. Edit the +file ~/.config/kdeglobals and add a section containing the following: + + [Development] + AutoCheckAccelerators=false + ++ +See https://stackoverflow.com/a/32711483 and +https://bugs.kde.org/show_bug.cgi?id=337491 for more details. diff --git a/doc/user_guide/en/images/ft4_decodes.png b/doc/user_guide/en/images/ft4_decodes.png new file mode 100644 index 000000000..05d2083fd Binary files /dev/null and b/doc/user_guide/en/images/ft4_decodes.png differ diff --git a/doc/user_guide/en/images/ft4_waterfall.png b/doc/user_guide/en/images/ft4_waterfall.png new file mode 100644 index 000000000..07ed6398a Binary files /dev/null and b/doc/user_guide/en/images/ft4_waterfall.png differ diff --git a/doc/user_guide/en/install-windows.adoc b/doc/user_guide/en/install-windows.adoc index e3f75858c..786e9a294 100644 --- a/doc/user_guide/en/install-windows.adoc +++ b/doc/user_guide/en/install-windows.adoc @@ -1,11 +1,12 @@ // Status=review -Download and execute the package file {win32}, following these -instructions: +Download and execute the package file {win32} (WinXP, Vista, Win 7, +Win 8, Win10, 32-bit) or {win64} (Vista, Win 7, Win 8, Win10, 64-bit) +following these instructions: * Install _WSJT-X_ into its own directory, for example `C:\WSJTX` or ` C:\WSJT\WSJTX`, rather than the conventional location `C:\Program - Files (x86)\WSJTX`. + Files ...\WSJTX`. * All program files relating to _WSJT-X_ will be stored in the chosen installation directory and its subdirectories. @@ -29,26 +30,31 @@ TIP: Your computer may be configured so that this directory is [[OPENSSL]] -* image:LoTW_TLS_error.png[_WSJT-X_ LoTW download TLS error, role="right"] - From this version onward _WSJT-X_ requires the _OpenSSL_ libraries - to be installed. Suitable libraries may already be installed on your +* image:LoTW_TLS_error.png[_WSJT-X_ LoTW download TLS error, + role="right"] _WSJT-X_ requires the _OpenSSL_ libraries to be + installed. Suitable libraries may already be installed on your system, if they are not you will see this error shortly after startup. To fix this you need to install the _OpenSSL_ libraries. ** You can download a suitable _OpenSSL_ package for from - {win_openssl_packages}, you need the latest *Win32 v1.0.2 Lite* - version (Note it is the Win32 package even if you are using a - 64-bit Windows operating system) which at the time of writing was - {win32_openssl}. + {win_openssl_packages}, you need the latest *Windows v1.0.2 Lite* + version. For the 32-bit _WSJT-X_ build use the Win32 version of the + _OpenSSL_ libraries, for the 64-bit _WSJT-X_ use the Win64 version + of the _OpenSSL_ libraries (Note it is OK to install both versions + on a 64-bit system) which at the time of writing were + {win32_openssl} and {win64_openssl} respectively. ** Install the package and accept the default options, including the - option to copy the _OpenSSL_ DLLs to the Windows system directory - (this is important). + + option to copy the _OpenSSL_ DLLs to the Windows system + directory. There is no obligation to donate to the _OpenSSL_ + project, un-check all the donation options if desired. + NOTE: If you still get the same network error after installing the _OpenSSL_ libraries then you also need to install the {msvcpp_redist} component. From the download page select - `vcredist_x86.exe` and run it to install. + `vcredist_x86.exe` for use with the 32-bit _WSJT-X_ build or + `vcredist_x64.exe` with the 64-bit build, then run it to + install. TIP: If you cannot install the _OpenSSL_ libraries or do not have an Internet connection on the computer used to run diff --git a/doc/user_guide/en/introduction.adoc b/doc/user_guide/en/introduction.adoc index b48738190..f0d8e12e7 100644 --- a/doc/user_guide/en/introduction.adoc +++ b/doc/user_guide/en/introduction.adoc @@ -7,10 +7,10 @@ K1**JT**,`" while the suffix "`-X`" indicates that _WSJT-X_ started as an extended and experimental branch of the program _WSJT_. -_WSJT-X_ Version {VERSION_MAJOR}.{VERSION_MINOR} offers nine different -protocols or modes: *FT8*, *JT4*, *JT9*, *JT65*, *QRA64*, *ISCAT*, -*MSK144*, *WSPR*, and *Echo*. The first five are designed for making -reliable QSOs under extreme weak-signal conditions. They use nearly +_WSJT-X_ Version {VERSION_MAJOR}.{VERSION_MINOR} offers ten different +protocols or modes: *FT4*, *FT8*, *JT4*, *JT9*, *JT65*, *QRA64*, +*ISCAT*, *MSK144*, *WSPR*, and *Echo*. The first six are designed for +making reliable QSOs under weak-signal conditions. They use nearly identical message structure and source encoding. JT65 and QRA64 were designed for EME ("`moonbounce`") on the VHF/UHF bands and have also proven very effective for worldwide QRP communication on the HF bands. @@ -25,12 +25,19 @@ one-minute timed sequences of alternating transmission and reception, so a minimal QSO takes four to six minutes — two or three transmissions by each station, one sending in odd UTC minutes and the other even. FT8 is operationally similar but four times faster -(15-second T/R sequences) and less sensitive by a few dB. On the HF -bands, world-wide QSOs are possible with any of these modes using -power levels of a few watts (or even milliwatts) and compromise -antennas. On VHF bands and higher, QSOs are possible (by EME and -other propagation types) at signal levels 10 to 15 dB below those -required for CW. +(15-second T/R sequences) and less sensitive by a few dB. FT4 is +faster still (7.5 s T/R sequences) and especially well suited for +radio contesting. On the HF bands, world-wide QSOs are possible with +any of these modes using power levels of a few watts (or even +milliwatts) and compromise antennas. On VHF bands and higher, QSOs +are possible (by EME and other propagation types) at signal levels 10 +to 15 dB below those required for CW. + +Note that even though their T/R sequences are short, FT4 and FT8 are +classified as slow modes because their message frames are sent only +once per transmission. All fast modes in _WSJT-X_ send their message +frames repeatedly, as many times as will fit into the Tx sequence +length. *ISCAT*, *MSK144*, and optionally submodes *JT9E-H* are "`fast`" protocols designed to take advantage of brief signal enhancements from @@ -65,10 +72,10 @@ are available for all three platforms. *Version Numbers:* _WSJT-X_ release numbers have major, minor, and patch numbers separated by periods: for example, _WSJT-X_ Version -1.9.0. Temporary "`beta`" release candidates are sometimes made in +2.1.0. Temporary _beta release_ candidates are sometimes made in advance of a new general-availability release, in order to obtain user -feedback. For example, version 1.9.0-rc1, 1.9.0-rc2, etc., would -be beta releases leading up to the final release of v1.9.0. +feedback. For example, version 2.1.0-rc1, 2.1.0-rc2, etc., would +be beta releases leading up to the final release of v2.1.0. Release candidates should be used _only_ during a short testing period. They carry an implied obligation to provide feedback to the program development group. Candidate releases should not be used on diff --git a/doc/user_guide/en/new_features.adoc b/doc/user_guide/en/new_features.adoc index a90b52182..d940c1cc3 100644 --- a/doc/user_guide/en/new_features.adoc +++ b/doc/user_guide/en/new_features.adoc @@ -1,40 +1,15 @@ === New in Version {VERSION} -For quick reference, here's a short list of features and capabilities -added to _WSJT-X_ since Version 1.9.1: - -- New FT8 and MSK144 protocols with 77-bit payloads permit these enhancements: - -* Optimized contest messages for NA VHF, EU VHF, Field Day, RTTY Roundup - -* Full support for "/R" and "/P" calls in relevant contests - -* New logging features for contesting - -* Integration with {n1mm_logger} and {writelog} for contesting - -* Improved support for compound and nonstandard callsigns - -* Nearly equal (or better) sensitivity compared to old protocols - -* Lower false decode rates - -- Improved color highlighting of received messages - -- Improved WSPR sensitivity - -- Expanded and improved UDP messages sent to companion programs - -- Bug fixes and other minor tweaks to user interface - -IMPORTANT: Note that for FT8 and MSK144 there is no backward -compatibility with WSJT-X 1.9.1 and earlier. Everyone using these -modes should upgrade to WSJT-X 2.0 by January 1, 2019. - -IMPORTANT: _WSJT-X_ Version 2.0 drops support for Apple Mac OS X 10.9 -(Mavericks). It is possible to build from source for this operating -system version but the DMG installer package requires 10.10 or later. - +The most important feature added to _WSJT-X_ since Version 2.0.1 is +the new *FT4 protocol*, designed especially for radio contesting. It +has T/R sequence length 7.5 s, bandwidth 80 Hz, and threshold +sensitivity -17.5 dB. Version 2.1.0 also has improvements to FT8 +waveform generation, waterfall and spectrum display, contest logging, +rig control, the user interface, keyboard shortcuts, UDP messaging for +inter-program communication, and accessibility, as well as a number of +more minor enhancements and bug fixes. We now provide a separate +installation package for 64-bit Windows Vista and later, offering +significant improvements in decoding speed. === Documentation Conventions diff --git a/doc/user_guide/en/protocols.adoc b/doc/user_guide/en/protocols.adoc index f50096097..e0d4145e3 100644 --- a/doc/user_guide/en/protocols.adoc +++ b/doc/user_guide/en/protocols.adoc @@ -12,10 +12,11 @@ Special cases allow other information such as add-on callsign prefixes aim is to compress the most common messages used for minimally valid QSOs into a fixed 72-bit length. -The information payload for FT8 and MSK144 contains 77 bits. The 5 -additional bits are used to flag special message types used for FT8 -DXpedition Mode, contesting, nonstandard callsigns, and a few other -special types. +The information payload for FT4, FT8, and MSK144 contains 77 bits. +The 5 new bits added to the original 72 are used to flag special +message types signifying special message types used for FT8 DXpedition +Mode, contesting, nonstandard callsigns, and a few other +possibilities. A standard amateur callsign consists of a one- or two-character prefix, at least one of which must be a letter, followed by a digit @@ -67,18 +68,29 @@ _WSJT-X_ modes have continuous phase and constant envelope. [[SLOW_MODES]] === Slow Modes +[[FT4PRO]] +==== FT4 + +Forward error correction (FEC) in FT4 uses a low-density parity check +(LDPC) code with 77 information bits, a 14-bit cyclic redundancy check +(CRC), and 83 parity bits making a 174-bit codeword. It is thus +called an LDPC (174,91) code. Synchronization uses four 4×4 Costas +arrays, and ramp-up and ramp-down symbols are inserted at the start +and end of each transmission. Modulation is 4-tone frequency-shift +keying (4-GFSK) with Gaussian smoothing of frequency transitions. The +keying rate is 12000/576 = 20.8333 baud. Each transmitted symbol +conveys two bits, so the total number of channel symbols is 174/2 + 16 ++ 2 = 105. The total bandwidth is 4 × 20.8333 = 83.3 Hz. + [[FT8PRO]] ==== FT8 -Forward error correction (FEC) in FT8 uses a low-density parity check -(LDPC) code with 77 information bits, a 14-bit cyclic redundancy check -(CRC), and 83 parity bits making a 174-bit codeword. It is thus -called an LDPC (174,91) code. Synchronization uses 7×7 Costas arrays -at the beginning, middle, and end of each transmission. Modulation is -8-tone frequency-shift keying (8-FSK) at 12000/1920 = 6.25 baud. Each -transmitted symbol carries three bits, so the total number of channel -symbols is 174/3 + 21 = 79. The total occupied bandwidth is 8 × 6.25 -= 50 Hz. +FT8 uses the same LDPC (174,91) code as FT4. Modulation is 8-tone +frequency-shift keying (8-GFSK) at 12000/1920 = 6.25 baud. +Synchronization uses 7×7 Costas arrays at the beginning, middle, and +end of each transmission. Transmitted symbols carry three bits, so +the total number of channel symbols is 174/3 + 21 = 79. The total +occupied bandwidth is 8 × 6.25 = 50 Hz. [[JT4PRO]] ==== JT4 @@ -227,7 +239,8 @@ which the probability of decoding is 50% or higher. |=============================================================================== |Mode |FEC Type |(n,k) | Q|Modulation type|Keying rate (Baud)|Bandwidth (Hz) |Sync Energy|Tx Duration (s)|S/N Threshold (dB) -|FT8 |LDPC, r=1/2|(174,91)| 8| 8-FSK| 6.25 | 50.0 | 0.27| 12.6 | -21 +|FT4 |LDPC, r=1/2|(174,91)| 4| 4-GFSK| 20.8333 | 83.3 | 0.15| 5.04 | -17.5 +|FT8 |LDPC, r=1/2|(174,91)| 8| 8-GFSK| 6.25 | 50.0 | 0.27| 12.6 | -21 |JT4A |K=32, r=1/2|(206,72)| 2| 4-FSK| 4.375| 17.5 | 0.50| 47.1 | -23 |JT9A |K=32, r=1/2|(206,72)| 8| 9-FSK| 1.736| 15.6 | 0.19| 49.0 | -27 |JT65A |Reed Solomon|(63,12) |64|65-FSK| 2.692| 177.6 | 0.50| 46.8 | -25 @@ -246,6 +259,7 @@ comparable to tone spacing. [width="50%",cols="h,3*^",frame=topbot,options="header"] |===================================== |Mode |Tone Spacing |BW (Hz)|S/N (dB) +|FT4 |20.8333 | 83.3 |-17.5 |FT8 |6.25 | 50.0 |-21 |JT4A |4.375| 17.5 |-23 |JT4B |8.75 | 30.6 |-22 diff --git a/doc/user_guide/en/tutorial-example4.adoc b/doc/user_guide/en/tutorial-example4.adoc new file mode 100644 index 000000000..43be6af1a --- /dev/null +++ b/doc/user_guide/en/tutorial-example4.adoc @@ -0,0 +1,52 @@ +// Status=review +.Main Window: +- Select *FT4* on the *Mode* menu. +- Double-click on *Erase* to clear both text windows. + +.Wide Graph Settings: + +- *Bins/Pixel* = 7, *Start* = 100 Hz, *N Avg* = 1 +- Adjust the width of the Wide Graph window so that the upper +frequency limit is approximately 4000 Hz. + +.Open a Wave File: + +- Select *File | Open* and navigate to ++...\save\samples\FT4\000000_000002.wav+. The waterfall and Band +Activity window should look something like the following screen shots. +This sample file was recorded during a practice contest test session, so +most of the decoded messages use the *RTTY Roundup* message formats. + +[[X15]] +image::ft4_waterfall.png[align="left",alt="Wide Graph Decode FT4"] + +image::ft4_decodes.png[align="left"] + +- Click with the mouse anywhere on the waterfall display. The green Rx +frequency marker will jump to your selected frequency, and the Rx +frequency control on the main window will be updated accordingly. + +- Do the same thing with the *Shift* key held down. Now the red Tx +frequency marker and its associated control on the main window will +follow your frequency selections. + +- Do the same thing with the *Ctrl* key held down. Now the both colored +markers and both spinner controls will follow your selections. + +- Now double-click on any of the the lines of decoded text in the Band +Activity window. Any line will show similar behavior, setting +Rx frequency to that of the selected message and leaving Tx frequency +unchanged. To change both Rx and Tx frequencies, hold *Ctrl* down +when double-clicking. + +TIP: To avoid QRM from competing callers, it is frequently desirable +to answer a CQ on a different frequency from that of the CQing +station. The same is true when you tail-end another QSO. Choose a Tx +frequency that appears to be not in use. You might want to check the +box *Hold Tx Freq*. + +TIP: Keyboard shortcuts *Shift+F11* and *Shift+F12* provide an easy +way to move your FT4 Tx frequency down or up in 90 Hz steps. + +IMPORTANT: When finished with this Tutorial, don't forget to re-enter +your own callsign as *My Call* on the *Settings | General* tab. diff --git a/doc/user_guide/en/wsjtx-main.adoc b/doc/user_guide/en/wsjtx-main.adoc index 6b190e0a2..a3cea81e0 100644 --- a/doc/user_guide/en/wsjtx-main.adoc +++ b/doc/user_guide/en/wsjtx-main.adoc @@ -140,6 +140,10 @@ include::tutorial-example2.adoc[] === FT8 include::tutorial-example3.adoc[] +[[TUT_EX4]] +=== FT4 +include::tutorial-example4.adoc[] + [[MAKE_QSOS]] == Making QSOs include::make-qso.adoc[] diff --git a/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp b/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp deleted file mode 100644 index a666ed323..000000000 --- a/item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef DATE_TIME_AS_SECS_SINCE_EPOCH_DELEGATE_HPP_ -#define DATE_TIME_AS_SECS_SINCE_EPOCH_DELEGATE_HPP_ - -#include -#include -#include -#include -#include -#include -#include - -class DateTimeAsSecsSinceEpochDelegate final - : public QStyledItemDelegate -{ -public: - DateTimeAsSecsSinceEpochDelegate (QObject * parent = nullptr) - : QStyledItemDelegate {parent} - { - } - - static QVariant to_secs_since_epoch (QDateTime const& date_time) - { - return date_time.toMSecsSinceEpoch () / 1000ull; - } - - static QDateTime to_date_time (QModelIndex const& index, int role = Qt::DisplayRole) - { - return to_date_time (index.model ()->data (index, role)); - } - - static QDateTime to_date_time (QVariant const& value) - { - return QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC); - } - - QString displayText (QVariant const& value, QLocale const& locale) const override - { - return locale.toString (to_date_time (value), locale.dateFormat (QLocale::ShortFormat) + " hh:mm:ss"); - } - - QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const& /*option*/, QModelIndex const& /*index*/) const override - { - std::unique_ptr editor {new QDateTimeEdit {parent}}; - editor->setDisplayFormat (parent->locale ().dateFormat (QLocale::ShortFormat) + " hh:mm:ss"); - editor->setTimeSpec (Qt::UTC); // needed because it ignores time - // spec of the QDateTime that it is - // set from - return editor.release (); - } - - void setEditorData (QWidget * editor, QModelIndex const& index) const override - { - static_cast (editor)->setDateTime (to_date_time (index, Qt::EditRole)); - } - - void setModelData (QWidget * editor, QAbstractItemModel * model, QModelIndex const& index) const override - { - model->setData (index, to_secs_since_epoch (static_cast (editor)->dateTime ())); - } - - void updateEditorGeometry (QWidget * editor, QStyleOptionViewItem const& option, QModelIndex const& /*index*/) const override - { - editor->setGeometry (option.rect); - } -}; - -#endif diff --git a/item_delegates/FrequencyDelegate.cpp b/item_delegates/FrequencyDelegate.cpp new file mode 100644 index 000000000..b899c0563 --- /dev/null +++ b/item_delegates/FrequencyDelegate.cpp @@ -0,0 +1,27 @@ +#include "FrequencyDelegate.hpp" + +#include "widgets/FrequencyLineEdit.hpp" + +FrequencyDelegate::FrequencyDelegate (QObject * parent) + : QStyledItemDelegate {parent} +{ +} + +QWidget * FrequencyDelegate::createEditor (QWidget * parent, QStyleOptionViewItem const& + , QModelIndex const&) const +{ + auto * editor = new FrequencyLineEdit {parent}; + editor->setFrame (false); + return editor; +} + +void FrequencyDelegate::setEditorData (QWidget * editor, QModelIndex const& index) const +{ + static_cast (editor)->frequency (index.model ()->data (index, Qt::EditRole).value ()); +} + +void FrequencyDelegate::setModelData (QWidget * editor, QAbstractItemModel * model, QModelIndex const& index) const +{ + model->setData (index, static_cast (editor)->frequency (), Qt::EditRole); +} + diff --git a/item_delegates/FrequencyDelegate.hpp b/item_delegates/FrequencyDelegate.hpp new file mode 100644 index 000000000..76fc5545d --- /dev/null +++ b/item_delegates/FrequencyDelegate.hpp @@ -0,0 +1,21 @@ +#ifndef FREQUENCY_DELEGATE_HPP_ +#define FREQUENCY_DELEGATE_HPP_ + +#include + +// +// Class FrequencyDelegate +// +// Item delegate for editing a frequency in Hertz but displayed in MHz +// +class FrequencyDelegate final + : public QStyledItemDelegate +{ +public: + explicit FrequencyDelegate (QObject * parent = nullptr); + QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; + void setEditorData (QWidget * editor, QModelIndex const&) const override; + void setModelData (QWidget * editor, QAbstractItemModel *, QModelIndex const&) const override; +}; + +#endif diff --git a/item_delegates/FrequencyDeltaDelegate.cpp b/item_delegates/FrequencyDeltaDelegate.cpp new file mode 100644 index 000000000..40d90dc58 --- /dev/null +++ b/item_delegates/FrequencyDeltaDelegate.cpp @@ -0,0 +1,26 @@ +#include "FrequencyDeltaDelegate.hpp" + +#include "widgets/FrequencyDeltaLineEdit.hpp" + +FrequencyDeltaDelegate::FrequencyDeltaDelegate (QObject * parent) + : QStyledItemDelegate {parent} +{ +} + +QWidget * FrequencyDeltaDelegate::createEditor (QWidget * parent, QStyleOptionViewItem const& + , QModelIndex const&) const +{ + auto * editor = new FrequencyDeltaLineEdit {parent}; + editor->setFrame (false); + return editor; +} + +void FrequencyDeltaDelegate::setEditorData (QWidget * editor, QModelIndex const& index) const +{ + static_cast (editor)->frequency_delta (index.model ()->data (index, Qt::EditRole).value ()); +} + +void FrequencyDeltaDelegate::setModelData (QWidget * editor, QAbstractItemModel * model, QModelIndex const& index) const +{ + model->setData (index, static_cast (editor)->frequency_delta (), Qt::EditRole); +} diff --git a/item_delegates/FrequencyDeltaDelegate.hpp b/item_delegates/FrequencyDeltaDelegate.hpp new file mode 100644 index 000000000..121bc3d94 --- /dev/null +++ b/item_delegates/FrequencyDeltaDelegate.hpp @@ -0,0 +1,21 @@ +#ifndef FREQUENCY_DELTA_DELEGATE_HPP_ +#define FREQUENCY_DELTA_DELEGATE_HPP_ + +#include + +// +// Class FrequencyDeltaDelegate +// +// Item delegate for editing a frequency delta in Hertz but displayed in MHz +// +class FrequencyDeltaDelegate final + : public QStyledItemDelegate +{ +public: + explicit FrequencyDeltaDelegate (QObject * parent = nullptr); + QWidget * createEditor (QWidget * parent, QStyleOptionViewItem const&, QModelIndex const&) const override; + void setEditorData (QWidget * editor, QModelIndex const&) const override; + void setModelData (QWidget * editor, QAbstractItemModel *, QModelIndex const&) const override; +}; + +#endif diff --git a/item_delegates/item_delegates.pri b/item_delegates/item_delegates.pri index 153ad4271..819cb2e0c 100644 --- a/item_delegates/item_delegates.pri +++ b/item_delegates/item_delegates.pri @@ -1,12 +1,13 @@ SOURCES += \ item_delegates/ForeignKeyDelegate.cpp \ - item_delegates/FrequencyItemDelegate.cpp \ + item_delegates/FrequencyDelegate.cpp \ + item_delegates/FrequencyDeltaDelegate.cpp \ item_delegates/CallsignDelegate.cpp \ item_delegates/MaidenheadLocatorItemDelegate.cpp HEADERS += \ item_delegates/ForeignKeyDelegate.hpp \ - item_delegates/FrequencyItemDelegate.hpp \ + item_delegates/FrequencyDelegate.hpp \ + item_delegates/FrequencyDeltaDelegate.hpp \ item_delegates/CallsignDelegate.hpp \ - item_delegates/MaidenheadLocatorDelegate.hpp \ - item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp + item_delegates/MaidenheadLocatorDelegate.hpp diff --git a/lib/77bit/77bit.txt b/lib/77bit/77bit.txt index ef370c111..89b481b6c 100644 --- a/lib/77bit/77bit.txt +++ b/lib/77bit/77bit.txt @@ -22,15 +22,10 @@ i3.n3 Example message Bits Total Purpose 2 PA3XYZ/P GM4ABC/P R JO22 28 1 28 1 1 15 74 EU VHF contest 3 TU; W9XYZ K1ABC R 579 MA 1 28 28 1 3 13 74 ARRL RTTY Roundup 4 PJ4/KA1ABC RR73 12 58 1 2 1 74 Nonstandard calls -5 ... tbd +5 TU; W9XYZ K1ABC R-07 FN 1 28 28 1 7 9 74 WWROF contest ? 6 ... tbd 7 ... tbd ---------------------------------------------------------------------------------- -In case we need them, later: - -5 TU; W9XYZ K1ABC R 579 8 MA 1 28 28 1 3 6 7 74 CQ WW RTTY -6 TU; W9XYZ K1ABC R 579 MA 1 28 28 1 3 13 74 CQ WPX RTTY ----------------------------------------------------------------------------------- NB: three 74-bit message types and two 71-bit message subtypes are still TBD. ---------------------------------------------------------------------------------- diff --git a/lib/77bit/messages.txt b/lib/77bit/messages.txt index 54fd44b05..aa4ab0789 100644 --- a/lib/77bit/messages.txt +++ b/lib/77bit/messages.txt @@ -72,7 +72,18 @@ CQ W9XYZ EN37 W9XYZ R-09 YW18FIFA RRR YW18FIFA 73 -10. Other stuff + +10. WWROF FT8/FT4 contest +----------------------------------------------------------- +CQ TEST K1ABC FN42 + K1ABC W9XYZ -16 EN +W9XYZ K1ABC R-07 FN + K1ABC W9XYZ RR73 + K1ABC G3AAA -11 IO +TU; G3AAA K1ABC R-09 FN + K1ABC G3AAA RR73 + +11. Other stuff ----------------------------------------------------------- TNX BOB 73 GL CQ YW18FIFA diff --git a/lib/77bit/packjt77.f90 b/lib/77bit/packjt77.f90 index 1ee37f5c1..1f9ed9a19 100644 --- a/lib/77bit/packjt77.f90 +++ b/lib/77bit/packjt77.f90 @@ -172,6 +172,10 @@ subroutine pack77(msg0,i3,n3,c77) call pack77_4(nwords,w,i3,n3,c77) if(i3.ge.0) go to 900 +! Check Type 5 (WWROF contest exchange) + call pack77_5(nwords,w,i3,n3,c77) + if(i3.ge.0) go to 900 + ! It defaults to free text 800 i3=0 n3=0 @@ -204,6 +208,7 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) character*6 cexch,grid6 character*4 grid4,cserial character*3 csec(NSEC) + character*2 cfield character*38 c integer hashmy10,hashmy12,hashmy22,hashdx10,hashdx12,hashdx22 logical unpk28_success,unpk77_success @@ -491,8 +496,31 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) else msg='CQ '//trim(call_2) endif + + else if(i3.eq.5) then +! 5 TU; W9XYZ K1ABC R-09 FN 1 28 28 1 7 9 74 WWROF contest + read(c77,1041) itu,n28a,n28b,ir,irpt,nexch,i3 +1041 format(b1,2b28.28,b1,b7.7,b9.9,b3.3) + call unpack28(n28a,call_1,unpk28_success) + if(.not.unpk28_success) unpk77_success=.false. + call unpack28(n28b,call_2,unpk28_success) + if(.not.unpk28_success) unpk77_success=.false. + write(crpt,'(i3.2)') irpt-35 + if(crpt(1:1).eq.' ') crpt(1:1)='+' + n1=nexch/18 + n2=nexch - 18*n1 + cfield(1:1)=char(ichar('A')+n1) + cfield(2:2)=char(ichar('A')+n2) + if(itu.eq.0 .and. ir.eq.0) msg=trim(call_1)//' '//trim(call_2)// & + ' '//crpt//' '//cfield + if(itu.eq.1 .and. ir.eq.0) msg='TU; '//trim(call_1)//' '//trim(call_2)// & + ' '//crpt//' '//cfield + if(itu.eq.0 .and. ir.eq.1) msg=trim(call_1)//' '//trim(call_2)// & + ' R'//crpt//' '//cfield + if(itu.eq.1 .and. ir.eq.1) msg='TU; '//trim(call_1)//' '//trim(call_2)// & + ' R'//crpt//' '//cfield endif - if(msg(1:4).eq.'CQ <') unpk77_success=.false. +! if(msg(1:4).eq.'CQ <') unpk77_success=.false. return end subroutine unpack77 @@ -1040,12 +1068,11 @@ subroutine pack77_3(nwords,w,i3,n3,c77) call chkcall(w(i1+1),bcall_2,ok2) if(.not.ok1 .or. .not.ok2) go to 900 crpt=w(nwords-1)(1:3) + if(index(crpt,'-').ge.1 .or. index(crpt,'+').ge.1) go to 900 if(crpt(1:1).eq.'5' .and. crpt(2:2).ge.'2' .and. crpt(2:2).le.'9' .and. & crpt(3:3).eq.'9') then nserial=0 read(w(nwords),*,err=1) nserial -!1 i3=3 -! n3=0 endif 1 mult=' ' imult=-1 @@ -1150,6 +1177,60 @@ subroutine pack77_4(nwords,w,i3,n3,c77) 900 return end subroutine pack77_4 +subroutine pack77_5(nwords,w,i3,n3,c77) +! Check Type 5 (WWROF contest exchange) + + character*13 w(19) + character*77 c77 + character*6 bcall_1,bcall_2 + character*3 mult + character crpt*4 + character c1*1,c2*2 + logical ok1,ok2 + + if(nwords.eq.4 .or. nwords.eq.5 .or. nwords.eq.6) then + i1=1 + if(trim(w(1)).eq.'TU;') i1=2 + call chkcall(w(i1),bcall_1,ok1) + call chkcall(w(i1+1),bcall_2,ok2) + if(.not.ok1 .or. .not.ok2) go to 900 + crpt=w(nwords-1)(1:4) + if(index(crpt,'-').lt.1 .and. index(crpt,'+').lt.1) go to 900 + + c1=crpt(1:1) + c2=crpt(1:2) + irpt=-1 + if(c1.eq.'+' .or. c1.eq.'-') then + ir=0 + read(w(nwords-1),*,err=900) irpt + irpt=irpt+35 + else if(c2.eq.'R+' .or. c2.eq.'R-') then + ir=1 + read(w(nwords-1)(2:),*) irpt + irpt=irpt+35 + endif + if(irpt.eq.-1 .or. len(trim(w(nwords))).ne.2) go to 900 + c2=w(nwords)(1:2) + n1=ichar(c2(1:1)) - ichar('A') + n2=ichar(c2(2:2)) - ichar('A') + if(n1.lt.0 .or. n1.gt.17) go to 900 + if(n2.lt.0 .or. n2.gt.17) go to 900 + nexch=18*n1 + n2 + i3=5 + n3=0 + itu=0 + if(trim(w(1)).eq.'TU;') itu=1 + call pack28(w(1+itu),n28a) + call pack28(w(2+itu),n28b) +! 5 TU; W9XYZ K1ABC R-09 FN 1 28 28 1 7 9 74 WWROF contest + write(c77,1010) itu,n28a,n28b,ir,irpt,nexch,i3 +1010 format(b1,2b28.28,b1,b7.7,b9.9,b3.3) + + end if + +900 return +end subroutine pack77_5 + subroutine packtext77(c13,c71) character*13 c13,w diff --git a/lib/addit.f90 b/lib/addit.f90 index 48082833f..33ed5a289 100644 --- a/lib/addit.f90 +++ b/lib/addit.f90 @@ -12,18 +12,22 @@ subroutine addit(itone,nfsample,nsym,nsps,ifreq,sig,dat) dphi=0. iters=1 - if(nsym.eq.79) iters=2 + if(nsym.eq.79) iters=2 !FT8 + if(nsym.eq.103) iters=5 !FT4 + do iter=1,iters f=ifreq phi=0. ntot=nsym*tsym/dt k=12000 !Start audio at t = 1.0 s t=0. - if(nsym.eq.79) k=12000 + (iter-1)*12000*30 !Special case for FT8 + if(nsym.eq.79) k=12000 + (iter-1)*12000*30 !Special case for FT8 + if(nsym.eq.103) k=12000 + (iter-1)*12000*10 !Special case for FT4 isym0=-1 do i=1,ntot t=t+dt isym=nint(t/tsym) + 1 + if(isym.gt.nsym) exit if(isym.ne.isym0) then freq=f + itone(isym)*baud dphi=twopi*freq*dt @@ -59,7 +63,7 @@ subroutine addcw(icw,ncw,ifreq,sig,dat) phi=0. k=12000 !Start audio at t = 1.0 s t=0. - npts=60*12000 + npts=59*12000 x=0. do i=1,npts t=t+dt diff --git a/lib/allsim.f90 b/lib/allsim.f90 index 2d948b64f..59d3fa264 100644 --- a/lib/allsim.f90 +++ b/lib/allsim.f90 @@ -1,6 +1,6 @@ program allsim -! Generate simulated data for WSJT-X slow modes: JT4, JT9, JT65, QRA64, +! Generate simulated data for WSJT-X modes: JT4, JT9, JT65, FT8, FT4, QRA64, ! and WSPR. Also unmodulated carrier and 20 WPM CW. @@ -15,6 +15,7 @@ program allsim logical*1 bcontest real*4 dat(NMAX) character message*22,msgsent*22,arg*8,mygrid*6 + character*37 msg37,msgsent37 nargs=iargc() if(nargs.ne.1) then @@ -60,15 +61,20 @@ program allsim call gen4(message,0,msgsent,itone,itype) call addit(itone,11025,206,2520,1200,sig,dat) !JT4 - i3bit=0 ! ### TEMPORARY ??? ### - call genft8(message,mygrid,bcontest,i3bit,msgsent,msgbits,itone) + i3=-1 + n3=-1 + call genft8(message,i3,n3,msgsent,msgbits,itone) call addit(itone,12000,79,1920,1400,sig,dat) !FT8 + msg37=message//' ' + call genft4(msg37,0,msgsent37,itone) + call addit(itone,12000,103,512,1600,sig,dat) !FT4 + call genqra64(message,0,msgsent,itone,itype) - call addit(itone,12000,84,6912,1600,sig,dat) !QRA64 + call addit(itone,12000,84,6912,1800,sig,dat) !QRA64 call gen65(message,0,msgsent,itone,itype) - call addit(itone,11025,126,4096,1800,sig,dat) !JT65 + call addit(itone,11025,126,4096,2000,sig,dat) !JT65 iwave(1:npts)=nint(rms*dat(1:npts)) diff --git a/lib/astrosub.f90 b/lib/astrosub.f90 index 49551ce3e..0670d66dc 100644 --- a/lib/astrosub.f90 +++ b/lib/astrosub.f90 @@ -1,55 +1,97 @@ -subroutine astrosub(nyear,month,nday,uth8,freq8,mygrid,hisgrid, & - AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8,ntsky,ndop,ndop00, & - RAMoon8,DecMoon8,Dgrd8,poloffset8,xnr8,techo8,width1,width2,bTx, & - AzElFileName,jpleph) +module astro_module + use, intrinsic :: iso_c_binding, only : c_int, c_double, c_bool, c_char, c_ptr, c_size_t, c_f_pointer + implicit none - implicit real*8 (a-h,o-z) - character*6 mygrid,hisgrid,c1*1 - character*6 AzElFileName*(*),jpleph*(*) - character*256 jpleph_file_name - logical*1 bTx - common/jplcom/jpleph_file_name + private + public :: astrosub - jpleph_file_name=jpleph +contains - call astro0(nyear,month,nday,uth8,freq8,mygrid,hisgrid, & - AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8,ntsky,ndop,ndop00, & - dbMoon8,RAMoon8,DecMoon8,HA8,Dgrd8,sd8,poloffset8,xnr8,dfdt,dfdt0, & - width1,width2,xlst8,techo8) + subroutine astrosub(nyear,month,nday,uth8,freq8,mygrid_cp,mygrid_len, & + hisgrid_cp,hisgrid_len,AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8, & + ntsky,ndop,ndop00,RAMoon8,DecMoon8,Dgrd8,poloffset8,xnr8,techo8,width1, & + width2,bTx,AzElFileName_cp,AzElFileName_len,jpleph_cp,jpleph_len) & + bind (C, name="astrosub") - if (len_trim(AzElFileName) .eq. 0) go to 999 - imin=60*uth8 - isec=3600*uth8 - ih=uth8 - im=mod(imin,60) - is=mod(isec,60) - open(15,file=AzElFileName,status='unknown',err=900) - c1='R' - nRx=1 - if(bTx) then - c1='T' - nRx=0 - endif - AzAux=0. - ElAux=0. - nfreq=freq8/1000000 - doppler=ndop - doppler00=ndop00 - write(15,1010,err=10) ih,im,is,AzMoon8,ElMoon8, & - ih,im,is,AzSun8,ElSun8, & - ih,im,is,AzAux,ElAux, & - nfreq,doppler,dfdt,doppler00,dfdt0,c1 -! TXFirst,TRPeriod,poloffset,Dgrd,xnr,ave,rms,nRx + integer, parameter :: dp = selected_real_kind(15, 50) + + integer(c_int), intent(in), value :: nyear, month, nday + real(c_double), intent(in), value :: uth8, freq8 + real(c_double), intent(out) :: AzSun8, ElSun8, AzMoon8, ElMoon8, AzMoonB8, & + ElMoonB8, Ramoon8, DecMoon8, Dgrd8, poloffset8, xnr8, techo8, width1, & + width2 + integer(c_int), intent(out) :: ntsky, ndop, ndop00 + logical(c_bool), intent(in), value :: bTx + type(c_ptr), intent(in), value :: mygrid_cp, hisgrid_cp, AzElFileName_cp, jpleph_cp + integer(c_size_t), intent(in), value :: mygrid_len, hisgrid_len, AzElFileName_len, jpleph_len + + character(len=6) :: mygrid, hisgrid + character(kind=c_char, len=:), allocatable :: AzElFileName + character(len=1) :: c1 + integer :: ih, im, imin, is, isec, nfreq, nRx + real(dp) :: AzAux, ElAux, dbMoon8, dfdt, dfdt0, doppler, doppler00, HA8, sd8, xlst8 + character*256 jpleph_file_name + common/jplcom/jpleph_file_name + + block + character(kind=c_char, len=mygrid_len), pointer :: mygrid_fp + character(kind=c_char, len=hisgrid_len), pointer :: hisgrid_fp + character(kind=c_char, len=AzElFileName_len), pointer :: AzElFileName_fp + character(kind=c_char, len=jpleph_len), pointer :: jpleph_fp + call c_f_pointer(cptr=mygrid_cp, fptr=mygrid_fp) + mygrid = mygrid_fp + mygrid_fp => null() + call c_f_pointer(cptr=hisgrid_cp, fptr=hisgrid_fp) + hisgrid = hisgrid_fp + hisgrid_fp => null() + call c_f_pointer(cptr=AzElFileName_cp, fptr=AzElFileName_fp) + AzElFileName = AzElFileName_fp + AzElFileName_fp => null() + call c_f_pointer(cptr=jpleph_cp, fptr=jpleph_fp) + jpleph_file_name = jpleph_fp + jpleph_fp => null() + end block + + call astro0(nyear,month,nday,uth8,freq8,mygrid,hisgrid, & + AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8,ntsky,ndop,ndop00, & + dbMoon8,RAMoon8,DecMoon8,HA8,Dgrd8,sd8,poloffset8,xnr8,dfdt,dfdt0, & + width1,width2,xlst8,techo8) + + if (len_trim(AzElFileName) .eq. 0) go to 999 + imin=60*uth8 + isec=3600*uth8 + ih=uth8 + im=mod(imin,60) + is=mod(isec,60) + open(15,file=AzElFileName,status='unknown',err=900) + c1='R' + nRx=1 + if(bTx) then + c1='T' + nRx=0 + endif + AzAux=0. + ElAux=0. + nfreq=freq8/1000000 + doppler=ndop + doppler00=ndop00 + write(15,1010,err=10) ih,im,is,AzMoon8,ElMoon8, & + ih,im,is,AzSun8,ElSun8, & + ih,im,is,AzAux,ElAux, & + nfreq,doppler,dfdt,doppler00,dfdt0,c1 + ! TXFirst,TRPeriod,poloffset,Dgrd,xnr,ave,rms,nRx 1010 format( & - i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Moon'/ & - i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Sun'/ & - i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Source'/ & - i5,',',f8.1,',',f8.2,',',f8.1,',',f8.2,',Doppler, ',a1) -! i1,',',i3,',',f8.1,','f8.1,',',f8.1,',',f12.3,',',f12.3,',',i1,',RPol') -10 close(15) - go to 999 + i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Moon'/ & + i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Sun'/ & + i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Source'/ & + i5,',',f8.1,',',f8.2,',',f8.1,',',f8.2,',Doppler, ',a1) + ! i1,',',i3,',',f8.1,','f8.1,',',f8.1,',',f12.3,',',f12.3,',',i1,',RPol') +10 close(15) + go to 999 900 print*,'Error opening azel.dat' 999 return -end subroutine astrosub + end subroutine astrosub + +end module astro_module diff --git a/lib/azdist.f90 b/lib/azdist.f90 index 2fd26c3d7..41a8fc5bc 100644 --- a/lib/azdist.f90 +++ b/lib/azdist.f90 @@ -1,7 +1,7 @@ -subroutine azdist(grid1,grid2,utch,nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter) +subroutine azdist(MyGrid,HisGrid,utch,nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter) - character*(*) grid1,grid2 - character*6 MyGrid,HisGrid,mygrid0,hisgrid0 + character(len=*) :: MyGrid,HisGrid + character*6 mygrid0,hisgrid0 real*8 utch,utch0 logical HotABetter,IamEast real eltab(22),daztab(22) @@ -12,11 +12,6 @@ subroutine azdist(grid1,grid2,utch,nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter) data mygrid0/" "/,hisgrid0/" "/,utch0/-999.d0/ save - MyGrid=grid1//' ' - HisGrid=grid2//' ' - if(ichar(MyGrid(5:5)).eq.0) MyGrid(5:6)=' ' - if(ichar(HisGrid(5:5)).eq.0) HisGrid(5:6)=' ' - if(MyGrid.eq.HisGrid) then naz=0 nel=0 diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 218a6cbf7..8abdcb75f 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -7,6 +7,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) use jt65_decode use jt9_decode use ft8_decode + use ft4_decode include 'jt9com.f90' include 'timer_common.inc' @@ -27,6 +28,10 @@ subroutine multimode_decoder(ss,id2,params,nfsample) integer :: decoded end type counting_ft8_decoder + type, extends(ft4_decoder) :: counting_ft4_decoder + integer :: decoded + end type counting_ft4_decoder + real ss(184,NSMAX) logical baddata,newdat65,newdat9,single_decode,bVHF,bad0,newdat,ex integer*2 id2(NTMAX*12000) @@ -40,6 +45,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) type(counting_jt65_decoder) :: my_jt65 type(counting_jt9_decoder) :: my_jt9 type(counting_ft8_decoder) :: my_ft8 + type(counting_ft4_decoder) :: my_ft4 !cast C character arrays to Fortran character strings datetime=transfer(params%datetime, datetime) @@ -53,6 +59,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) my_jt65%decoded = 0 my_jt9%decoded = 0 my_ft8%decoded = 0 + my_ft4%decoded = 0 single_decode=iand(params%nexp_decode,32).ne.0 bVHF=iand(params%nexp_decode,64).ne.0 @@ -126,8 +133,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) n30fox(j)=n m=n30max-n if(len(trim(g2fox(j))).eq.4) then - call azdist(mygrid,g2fox(j),0.d0,nAz,nEl,nDmiles,nDkm, & - nHotAz,nHotABetter) + call azdist(mygrid,g2fox(j)//' ',0.d0,nAz,nEl,nDmiles, & + nDkm,nHotAz,nHotABetter) else nDkm=9999 endif @@ -142,6 +149,15 @@ subroutine multimode_decoder(ss,id2,params,nfsample) go to 800 endif + if(params%nmode.eq.5) then + call timer('decft4 ',0) + call my_ft4%decode(ft4_decoded,id2,params%nQSOProgress,params%nfqso, & + params%nutc,params%nfa,params%nfb,params%ndepth, & + logical(params%lapcqonly),ncontest,mycall,hiscall) + call timer('decft4 ',1) + go to 800 + endif + rms=sqrt(dot_product(float(id2(300000:310000)), & float(id2(300000:310000)))/10000.0) if(rms.lt.2.0) go to 800 @@ -258,7 +274,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) !$omp end parallel sections ! JT65 is not yet producing info for nsynced, ndecoded. -800 ndecoded = my_jt4%decoded + my_jt65%decoded + my_jt9%decoded + my_ft8%decoded +800 ndecoded = my_jt4%decoded + my_jt65%decoded + my_jt9%decoded + & + my_ft8%decoded + my_ft4%decoded write(*,1010) nsynced,ndecoded 1010 format('',2i4) call flush(6) @@ -500,7 +517,7 @@ contains decoded0=decoded annot=' ' - if(ncontest.eq.0 .and. nap.ne.0) then + if(nap.ne.0) then write(annot,'(a1,i1)') 'a',nap if(qual.lt.0.17) decoded0(37:37)='?' endif @@ -561,4 +578,44 @@ contains return end subroutine ft8_decoded + subroutine ft4_decoded (this,sync,snr,dt,freq,decoded,nap,qual) + use ft4_decode + implicit none + + class(ft4_decoder), intent(inout) :: this + real, intent(in) :: sync + integer, intent(in) :: snr + real, intent(in) :: dt + real, intent(in) :: freq + character(len=37), intent(in) :: decoded + character c1*12,c2*12,g2*4,w*4 + integer i0,i1,i2,i3,i4,i5,n30,nwrap + integer, intent(in) :: nap + real, intent(in) :: qual + character*2 annot + character*37 decoded0 + + decoded0=decoded + + annot=' ' + if(nap.ne.0) then + write(annot,'(a1,i1)') 'a',nap + if(qual.lt.0.17) decoded0(37:37)='?' + endif + + write(*,1001) params%nutc,snr,dt,nint(freq),decoded0,annot +1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,a2) + write(13,1002) params%nutc,nint(sync),snr,dt,freq,0,decoded0 +1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' FT4') + + call flush(6) + call flush(13) + + select type(this) + type is (counting_ft4_decoder) + this%decoded = this%decoded + 1 + end select + + return + end subroutine ft4_decoded end subroutine multimode_decoder diff --git a/lib/fast_decode.f90 b/lib/fast_decode.f90 index eebb73108..c3cadb6a7 100644 --- a/lib/fast_decode.f90 +++ b/lib/fast_decode.f90 @@ -1,4 +1,4 @@ -subroutine fast_decode(id2,narg,ntrperiod,line,mycall_12, & +subroutine fast_decode(id2,narg,trperiod,line,mycall_12, & hiscall_12) parameter (NMAX=30*12000) @@ -6,6 +6,7 @@ subroutine fast_decode(id2,narg,ntrperiod,line,mycall_12, & integer*2 id2a(NMAX) integer*2 id2b(NMAX) integer narg(0:14) + double precision trperiod real dat(30*12000) complex cdat(262145),cdat2(262145) real psavg(450) @@ -41,7 +42,7 @@ subroutine fast_decode(id2,narg,ntrperiod,line,mycall_12, & nhashcalls=narg(12) line(1:100)(1:1)=char(0) - if(t0.gt.float(ntrperiod)) go to 900 + if(t0.gt.trperiod) go to 900 if(t0.gt.t1) go to 900 if(nmode.eq.102) then @@ -53,7 +54,7 @@ subroutine fast_decode(id2,narg,ntrperiod,line,mycall_12, & cdat2=cdat ndat=ndat0 call wav11(id2,ndat,dat) - nzz=11025*ntrperiod + nzz=11025*int(trperiod) !beware if fractional T/R period ever used here if(ndat.lt.nzz) dat(ndat+1:nzz)=0.0 ndat=min(ndat,30*11025) call ana932(dat,ndat,cdat,npts) !Make downsampled analytic signal diff --git a/lib/four2a.f90 b/lib/four2a.f90 index 57c7239e1..337ca15c3 100644 --- a/lib/four2a.f90 +++ b/lib/four2a.f90 @@ -19,6 +19,7 @@ subroutine four2a(a,nfft,ndim,isign,iform) ! This version of four2a makes calls to the FFTW library to do the ! actual computations. + use fftw3 parameter (NPMAX=2100) !Max numberf of stored plans parameter (NSMALL=16384) !Max size of "small" FFTs complex a(nfft) !Array to be transformed @@ -29,7 +30,6 @@ subroutine four2a(a,nfft,ndim,isign,iform) logical found_plan data nplan/0/ !Number of stored plans common/patience/npatience,nthreads !Patience and threads for FFTW plans - include 'fftw3.f90' !FFTW definitions save plan,nplan,nn,ns,nf,nl if(nfft.lt.0) go to 999 @@ -107,7 +107,7 @@ subroutine four2a(a,nfft,ndim,isign,iform) !$omp end critical(fftw) end if enddo - + call fftwf_cleanup() nplan=0 !$omp end critical(four2a) diff --git a/lib/freqcal.f90 b/lib/freqcal.f90 index 540237f6e..80ce90c66 100644 --- a/lib/freqcal.f90 +++ b/lib/freqcal.f90 @@ -41,6 +41,7 @@ subroutine freqcal(id2,k,nkhz,noffset,ntol,line) endif smax=0. s=0. + ipk=-99 do i=ia,ib s(i)=real(cx(i))**2 + aimag(cx(i))**2 if(s(i).gt.smax) then @@ -48,25 +49,32 @@ subroutine freqcal(id2,k,nkhz,noffset,ntol,line) ipk=i endif enddo - - call peakup(s(ipk-1),s(ipk),s(ipk+1),dx) - fpeak=df * (ipk+dx) - ap=(fpeak/fs+1.0/(2.0*NFFT)) - an=(fpeak/fs-1.0/(2.0*NFFT)) - sp=sum(id2((k-NFFT):k-1)*cmplx(cos(xi*ap),-sin(xi*ap))) - sn=sum(id2((k-NFFT):k-1)*cmplx(cos(xi*an),-sin(xi*an))) - fpeak=fpeak+fs*(abs(sp)-abs(sn))/(abs(sp)+abs(sn))/(2*NFFT) - xsum=0. - nsum=0 - do i=ia,ib - if(abs(i-ipk).gt.10) then - xsum=xsum+s(i) - nsum=nsum+1 - endif - enddo - ave=xsum/nsum - snr=db(smax/ave) - pave=db(ave) + 8.0 + + if(ipk.ge.1) then + call peakup(s(ipk-1),s(ipk),s(ipk+1),dx) + fpeak=df * (ipk+dx) + ap=(fpeak/fs+1.0/(2.0*NFFT)) + an=(fpeak/fs-1.0/(2.0*NFFT)) + sp=sum(id2((k-NFFT):k-1)*cmplx(cos(xi*ap),-sin(xi*ap))) + sn=sum(id2((k-NFFT):k-1)*cmplx(cos(xi*an),-sin(xi*an))) + fpeak=fpeak+fs*(abs(sp)-abs(sn))/(abs(sp)+abs(sn))/(2*NFFT) + xsum=0. + nsum=0 + do i=ia,ib + if(abs(i-ipk).gt.10) then + xsum=xsum+s(i) + nsum=nsum+1 + endif + enddo + ave=xsum/nsum + snr=db(smax/ave) + pave=db(ave) + 8.0 + else + snr=-99.9 + pave=-99.9 + fpeak=-99.9 + ferr=-99.9 + endif cflag=' ' if(snr.lt.20.0) cflag='*' n=n+1 @@ -77,7 +85,7 @@ subroutine freqcal(id2,k,nkhz,noffset,ntol,line) ncal=1 ferr=fpeak-noffset write(line,1100) nhr,nmin,nsec,nkhz,ncal,noffset,fpeak,ferr,pave, & - snr,cflag,char(0) + snr,cflag,char(0) 1100 format(i2.2,':',i2.2,':',i2.2,i7,i3,i6,2f10.3,2f7.1,2x,a1,a1) 900 return diff --git a/lib/fsk4hf/ft2_params.f90 b/lib/fsk4hf/ft2_params.f90 new file mode 100644 index 000000000..351119b4b --- /dev/null +++ b/lib/fsk4hf/ft2_params.f90 @@ -0,0 +1,12 @@ +! LDPC (128,90) code +parameter (KK=90) !Information bits (77 + CRC13) +parameter (ND=128) !Data symbols +parameter (NS=16) !Sync symbols (2x8) +parameter (NN=NS+ND) !Total channel symbols (144) +parameter (NSPS=160) !Samples per symbol at 12000 S/s +parameter (NZ=NSPS*NN) !Samples in full 1.92 s waveform (23040) +parameter (NMAX=2.5*12000) !Samples in iwave (36,000) +parameter (NFFT1=400, NH1=NFFT1/2) !Length of FFTs for symbol spectra +parameter (NSTEP=NSPS/4) !Rough time-sync step size +parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps) +parameter (NDOWN=16) !Downsample factor diff --git a/lib/fsk4hf/ft2d.f90 b/lib/fsk4hf/ft2d.f90 new file mode 100644 index 000000000..fda1f1826 --- /dev/null +++ b/lib/fsk4hf/ft2d.f90 @@ -0,0 +1,335 @@ +program ft2d + + use crc + use packjt77 + include 'ft2_params.f90' + character arg*8,message*37,c77*77,infile*80,fname*16,datetime*11 + character*37 decodes(100) + character*120 data_dir + character*90 dmsg + complex c2(0:NMAX/16-1) !Complex waveform + complex cb(0:NMAX/16-1) + complex cd(0:144*10-1) !Complex waveform + complex c1(0:9),c0(0:9) + complex ccor(0:1,144) + complex csum,cterm,cc0,cc1,csync1,csync2 + complex csync(16),csl(0:159) + real*8 fMHz + + real a(5) + real rxdata(128),llr(128) !Soft symbols + real llr2(128) + real sbits(144),sbits1(144),sbits3(144) + real ps(0:8191),psbest(0:8191) + real candidates(100,2) + real savg(NH1),sbase(NH1) + integer ihdr(11) + integer*2 iwave(NMAX) !Generated full-length waveform + integer*1 message77(77),apmask(128),cw(128) + integer*1 hbits(144),hbits1(144),hbits3(144) + integer*1 s16(16),s45(45) + logical unpk77_success + data s16/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0/ + data s45/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,1,1,1,1,0,0,1,0,0,0,1,1,0,1,0,0,0,1,1,1,0,0/ + + fs=12000.0/NDOWN !Sample rate + dt=1/fs !Sample interval after downsample (s) + tt=NSPS*dt !Duration of "itone" symbols (s) + baud=1.0/tt !Keying rate for "itone" symbols (baud) + txt=NZ*dt !Transmission length (s) + twopi=8.0*atan(1.0) + h=0.800 !h=0.8 seems to be optimum for AWGN sensitivity (not for fading) + + dphi=twopi/2*baud*h*dt*16 ! dt*16 is samp interval after downsample + dphi0=-1*dphi + dphi1=+1*dphi + phi0=0.0 + phi1=0.0 + do i=0,9 + c1(i)=cmplx(cos(phi1),sin(phi1)) + c0(i)=cmplx(cos(phi0),sin(phi0)) + phi1=mod(phi1+dphi1,twopi) + phi0=mod(phi0+dphi0,twopi) + enddo + the=twopi*h/2.0 + cc1=cmplx(cos(the),-sin(the)) + cc0=cmplx(cos(the),sin(the)) + + k=0 + do j=1,16 + dphi1=(2*s16(j)-1)*dphi + phi1=0.0 + do i=0,9 + csl(k)=cmplx(cos(phi1),sin(phi1)) + phi1=mod(phi1+dphi1,twopi) + k=k+1 + enddo + enddo + + nargs=iargc() + if(nargs.lt.1) then + print*,'Usage: ft2d [-a ] [-f fMHz] file1 [file2 ...]' + go to 999 + endif + iarg=1 + data_dir="." + call getarg(iarg,arg) + if(arg(1:2).eq.'-a') then + call getarg(iarg+1,data_dir) + iarg=iarg+2 + endif + call getarg(iarg,arg) + if(arg(1:2).eq.'-f') then + call getarg(iarg+1,arg) + read(arg,*) fMHz + iarg=iarg+2 + endif + ncoh=1 + + do ifile=iarg,nargs + call getarg(ifile,infile) + j2=index(infile,'.wav') + open(10,file=infile,status='old',access='stream') + read(10,end=999) ihdr,iwave + read(infile(j2-4:j2-1),*) nutc + datetime=infile(j2-11:j2-1) + close(10) + candidates=0.0 + ncand=0 + call getcandidates2(iwave,375.0,3000.0,0.2,2200.0,100,savg,candidates,ncand,sbase) + ndecodes=0 + do icand=1,ncand + f0=candidates(icand,1) + xsnr=1.0 + if( f0.le.375.0 .or. f0.ge.(5000.0-375.0) ) cycle + call ft2_downsample(iwave,f0,c2) ! downsample from 160s/Symbol to 10s/Symbol + +!c2=c2/sqrt(sum(abs(c2(0:NMAX/16-1)))) +!ishift=-1 +!rccbest=-99. +!do is=0,435 +!rcc=0.0 +! do id=10,10 +! rcc=rcc+abs(sum(conjg(c2(is:is+159-id))*c2(is+id:is+159)*csl(0:159-id)*conjg(csl(id:159)))) +! enddo +! if(rcc.gt.rccbest) then +! rccbest=rcc +! ishift=is +! endif +!write(21,*) is,rcc +!enddo + +! 750 samples/second here + ibest=-1 + sybest=-99. + dfbest=-1. + do if=-30,+30 + df=if + a=0. + a(1)=-df + call twkfreq1(c2,NMAX/16,fs,a,cb) + do is=0,374 + csync1=0. + cterm=1 + do ib=1,16 +! do ib=1,45 + i1=(ib-1)*10+is + if(s16(ib).eq.1) then +! if(s45(ib).eq.1) then + csync1=csync1+sum(cb(i1:i1+9)*conjg(c1(0:9)))*cterm + cterm=cterm*cc1 + else + csync1=csync1+sum(cb(i1:i1+9)*conjg(c0(0:9)))*cterm + cterm=cterm*cc0 + endif + enddo + if(abs(csync1).gt.sybest) then + ibest=is + sybest=abs(csync1) + dfbest=df + endif + enddo + enddo + + a=0. +!dfbest=1500.0-f0 + a(1)=-dfbest + + call twkfreq1(c2,NMAX/16,fs,a,cb) + +!ibest=197 + ib=ibest + + cd=cb(ib:ib+144*10-1) + s2=sum(cd*conjg(cd))/(10*144) + cd=cd/sqrt(s2) + do nseq=1,4 + if( nseq.eq.1 ) then ! noncoherent single-symbol detection + sbits1=0.0 + do ibit=1,144 + ib=(ibit-1)*10 + ccor(1,ibit)=sum(cd(ib:ib+9)*conjg(c1(0:9))) + ccor(0,ibit)=sum(cd(ib:ib+9)*conjg(c0(0:9))) + sbits1(ibit)=abs(ccor(1,ibit))-abs(ccor(0,ibit)) + hbits1(ibit)=0 + if(sbits1(ibit).gt.0) hbits1(ibit)=1 + enddo + sbits=sbits1 + hbits=hbits1 + sbits3=sbits1 + hbits3=hbits1 + elseif( nseq.ge.2 ) then + nbit=2*nseq-1 + numseq=2**(nbit) + ps=0 + do ibit=nbit/2+1,144-nbit/2 + ps=0.0 + pmax=0.0 + do iseq=0,numseq-1 + csum=0.0 + cterm=1.0 + k=1 + do i=nbit-1,0,-1 + ibb=iand(iseq/(2**i),1) + csum=csum+ccor(ibb,ibit-(nbit/2+1)+k)*cterm + if(ibb.eq.0) cterm=cterm*cc0 + if(ibb.eq.1) cterm=cterm*cc1 + k=k+1 + enddo + ps(iseq)=abs(csum) + if( ps(iseq) .gt. pmax ) then + pmax=ps(iseq) + ibflag=1 + endif + enddo + if( ibflag .eq. 1 ) then + psbest=ps + ibflag=0 + endif + call getbitmetric(2**(nbit/2),psbest,numseq,sbits3(ibit)) + hbits3(ibit)=0 + if(sbits3(ibit).gt.0) hbits3(ibit)=1 + enddo + sbits=sbits3 + hbits=hbits3 + endif + nsync_qual=count(hbits(1:16).eq.s16) +! if(nsync_qual.lt.10) exit + rxdata=sbits(17:144) + rxav=sum(rxdata(1:128))/128.0 + rx2av=sum(rxdata(1:128)*rxdata(1:128))/128.0 + rxsig=sqrt(rx2av-rxav*rxav) + rxdata=rxdata/rxsig + sigma=0.80 + llr(1:128)=2*rxdata/(sigma*sigma) +!xllrmax=maxval(abs(llr)) +!write(*,*) ifile,icand,nseq,nsync_qual + apmask=0 +!apmask(1:29)=1 +!llr(1:29)=xllrmax*(2*s45(17:45)-1) + max_iterations=40 + do ibias=0,0 + llr2=llr + if(ibias.eq.1) llr2=llr+0.4 + if(ibias.eq.2) llr2=llr-0.4 + call bpdecode128_90(llr2,apmask,max_iterations,message77,cw,nharderror,niterations) + if(nharderror.ge.0) exit + enddo + if(sum(message77).eq.0) cycle + if( nharderror.ge.0 ) then + write(c77,'(77i1)') message77(1:77) + call unpack77(c77,1,message,unpk77_success) + idupe=0 + do i=1,ndecodes + if(decodes(i).eq.message) idupe=1 + enddo + if(idupe.eq.1) goto 888 + ndecodes=ndecodes+1 + decodes(ndecodes)=message + nsnr=nint(xsnr) + freq=f0+dfbest +1210 format(a11,2i4,f6.2,f12.7,2x,a22,i3) + write(*,1212) datetime(8:11),nsnr,ibest/750.0,freq,message,'*',nseq,nharderror,nsync_qual +1212 format(a4,i4,2x,f5.3,f11.1,2x,a22,a1,i5,i5,i5) + goto 888 + endif + enddo ! nseq +888 continue + enddo !candidate list + enddo !files + + write(*,1120) +1120 format("") + +999 end program ft2d + +subroutine getbitmetric(ib,ps,ns,xmet) + real ps(0:ns-1) + xm1=0 + xm0=0 + do i=0,ns-1 + if( iand(i/ib,1) .eq. 1 .and. ps(i) .gt. xm1 ) xm1=ps(i) + if( iand(i/ib,1) .eq. 0 .and. ps(i) .gt. xm0 ) xm0=ps(i) + enddo + xmet=xm1-xm0 + return +end subroutine getbitmetric + +subroutine downsample2(ci,f0,co) + parameter(NI=144*160,NH=NI/2,NO=NI/16) ! downsample from 200 samples per symbol to 10 + complex ci(0:NI-1),ct(0:NI-1) + complex co(0:NO-1) + fs=12000.0 + df=fs/NI + ct=ci + call four2a(ct,NI,1,-1,1) !c2c FFT to freq domain + i0=nint(f0/df) + ct=cshift(ct,i0) + co=0.0 + co(0)=ct(0) + b=8.0 + do i=1,NO/2 + arg=(i*df/b)**2 + filt=exp(-arg) + co(i)=ct(i)*filt + co(NO-i)=ct(NI-i)*filt + enddo + co=co/NO + call four2a(co,NO,1,1,1) !c2c FFT back to time domain + return +end subroutine downsample2 + +subroutine ft2_downsample(iwave,f0,c) + +! Input: i*2 data in iwave() at sample rate 12000 Hz +! Output: Complex data in c(), sampled at 1200 Hz + + include 'ft2_params.f90' + parameter (NFFT2=NMAX/16) + integer*2 iwave(NMAX) + complex c(0:NMAX/16-1) + complex c1(0:NFFT2-1) + complex cx(0:NMAX/2) + real x(NMAX) + equivalence (x,cx) + + BW=4.0*75 + df=12000.0/NMAX + x=iwave + call four2a(x,NMAX,1,-1,0) !r2c FFT to freq domain + ibw=nint(BW/df) + i0=nint(f0/df) + c1=0. + c1(0)=cx(i0) + do i=1,NFFT2/2 + arg=(i-1)*df/bw + win=exp(-arg*arg) + c1(i)=cx(i0+i)*win + c1(NFFT2-i)=cx(i0-i)*win + enddo + c1=c1/NFFT2 + call four2a(c1,NFFT2,1,1,1) !c2c FFT back to time domain + c=c1(0:NMAX/16-1) + return +end subroutine ft2_downsample + diff --git a/lib/fsk4hf/ft2sim.f90 b/lib/fsk4hf/ft2sim.f90 new file mode 100644 index 000000000..ea0518a52 --- /dev/null +++ b/lib/fsk4hf/ft2sim.f90 @@ -0,0 +1,154 @@ +program ft2sim + +! Generate simulated signals for experimental "FT2" mode + + use wavhdr + use packjt77 + include 'ft2_params.f90' !Set various constants + parameter (NWAVE=NN*NSPS) + type(hdr) h !Header for .wav file + character arg*12,fname*17 + character msg37*37,msgsent37*37 + character c77*77 + complex c0(0:NMAX-1) + complex c(0:NMAX-1) + real wave(NMAX) + real dphi(0:NMAX-1) + real pulse(480) + integer itone(NN) + integer*1 msgbits(77) + integer*2 iwave(NMAX) !Generated full-length waveform + +! Get command-line argument(s) + nargs=iargc() + if(nargs.ne.8) then + print*,'Usage: ft2sim "message" f0 DT fdop del width nfiles snr' + print*,'Examples: ft2sim "K1ABC W9XYZ EN37" 1500.0 0.0 0.1 1.0 0 10 -18' + print*,' ft2sim "WA9XYZ/R KA1ABC/R FN42" 1500.0 0.0 0.1 1.0 0 10 -18' + print*,' ft2sim "K1ABC RR73; W9XYZ -11" 300 0 0 0 25 1 -10' + go to 999 + endif + call getarg(1,msg37) !Message to be transmitted + call getarg(2,arg) + read(arg,*) f0 !Frequency (only used for single-signal) + call getarg(3,arg) + read(arg,*) xdt !Time offset from nominal (s) + call getarg(4,arg) + read(arg,*) fspread !Watterson frequency spread (Hz) + call getarg(5,arg) + read(arg,*) delay !Watterson delay (ms) + call getarg(6,arg) + read(arg,*) width !Filter transition width (Hz) + call getarg(7,arg) + read(arg,*) nfiles !Number of files + call getarg(8,arg) + read(arg,*) snrdb !SNR_2500 + + nfiles=abs(nfiles) + twopi=8.0*atan(1.0) + fs=12000.0 !Sample rate (Hz) + dt=1.0/fs !Sample interval (s) + hmod=0.800 !Modulation index (0.5 is MSK, 1.0 is FSK) + tt=NSPS*dt !Duration of symbols (s) + baud=1.0/tt !Keying rate (baud) + txt=NZ*dt !Transmission length (s) + + bandwidth_ratio=2500.0/(fs/2.0) + sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb) + if(snrdb.gt.90.0) sig=1.0 + txt=NN*NSPS/12000.0 + + ! Source-encode, then get itone() + i3=-1 + n3=-1 + call pack77(msg37,i3,n3,c77) + read(c77,'(77i1)') msgbits + call genft2(msg37,0,msgsent37,itone,itype) + write(*,*) + write(*,'(a9,a37,3x,a7,i1,a1,i1)') 'Message: ',msgsent37,'i3.n3: ',i3,'.',n3 + write(*,1000) f0,xdt,txt,snrdb +1000 format('f0:',f9.3,' DT:',f6.2,' TxT:',f6.1,' SNR:',f6.1) + write(*,*) + if(i3.eq.1) then + write(*,*) ' mycall hiscall hisgrid' + write(*,'(28i1,1x,i1,1x,28i1,1x,i1,1x,i1,1x,15i1,1x,3i1)') msgbits(1:77) + else + write(*,'(a14)') 'Message bits: ' + write(*,'(77i1)') msgbits + endif + write(*,*) + write(*,'(a17)') 'Channel symbols: ' + write(*,'(79i1)') itone + write(*,*) + + call sgran() + +! The filtered frequency pulse + do i=1,480 + tt=(i-240.5)/160.0 + pulse(i)=gfsk_pulse(1.0,tt) + enddo + +! Define the instantaneous frequency waveform + dphi_peak=twopi*(hmod/2.0)/real(NSPS) + dphi=0.0 + do j=1,NN + ib=(j-1)*160 + ie=ib+480-1 + dphi(ib:ie)=dphi(ib:ie)+dphi_peak*pulse*(2*itone(j)-1) + enddo + + phi=0.0 + c0=0.0 + dphi=dphi+twopi*f0*dt + do j=0,NMAX-1 + c0(j)=cmplx(cos(phi),sin(phi)) + phi=mod(phi+dphi(j),twopi) + enddo + + c0(0:159)=c0(0:159)*(1.0-cos(twopi*(/(i,i=0,159)/)/320.0) )/2.0 + c0(145*160:145*160+159)=c0(145*160:145*160+159)*(1.0+cos(twopi*(/(i,i=0,159)/)/320.0 ))/2.0 + c0(146*160:)=0. + + k=nint((xdt+0.25)/dt) + c0=cshift(c0,-k) + ia=k + + do ifile=1,nfiles + c=c0 + if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c,NMAX,NWAVE,fs,delay,fspread) + c=sig*c + + ib=k + wave=real(c) + peak=maxval(abs(wave(ia:ib))) + nslots=1 + if(width.gt.0.0) call filt8(f0,nslots,width,wave) + + if(snrdb.lt.90) then + do i=1,NMAX !Add gaussian noise at specified SNR + xnoise=gran() + wave(i)=wave(i) + xnoise + enddo + endif + + gain=100.0 + if(snrdb.lt.90.0) then + wave=gain*wave + else + datpk=maxval(abs(wave)) + fac=32766.9/datpk + wave=fac*wave + endif + if(any(abs(wave).gt.32767.0)) print*,"Warning - data will be clipped." + iwave=nint(wave) + h=default_header(12000,NMAX) + write(fname,1102) ifile +1102 format('000000_',i6.6,'.wav') + open(10,file=fname,status='unknown',access='stream') + write(10) h,iwave !Save to *.wav file + close(10) + write(*,1110) ifile,xdt,f0,snrdb,fname +1110 format(i4,f7.2,f8.2,f7.1,2x,a17) + enddo +999 end program ft2sim diff --git a/lib/fsk4hf/ft4d.f90 b/lib/fsk4hf/ft4d.f90 new file mode 100644 index 000000000..d1bf262c1 --- /dev/null +++ b/lib/fsk4hf/ft4d.f90 @@ -0,0 +1,329 @@ +program ft4d + + use crc + use packjt77 + include 'ft4_params.f90' + character arg*8,message*37,c77*77,infile*80,fname*16,datetime*11 + character*37 decodes(100) + character*120 data_dir + character*90 dmsg + complex cd2(0:NMAX/16-1) !Complex waveform + complex cb(0:NMAX/16-1) + complex cd(0:76*20-1) !Complex waveform + complex csum,cterm + complex ctwk(80),ctwk2(80) + complex csymb(20) + complex cs(0:3,NN) + real s4(0:3,NN) + + real*8 fMHz + real ps(0:8191),psbest(0:8191) + real bmeta(152),bmetb(152),bmetc(152) + real s(NH1,NHSYM) + real a(5) + real llr(128),llr2(128),llra(128),llrb(128),llrc(128) + real s2(0:255) + real candidate(3,100) + real savg(NH1),sbase(NH1) + integer ihdr(11) + integer icos4(0:3) + integer*2 iwave(NMAX) !Generated full-length waveform + integer*1 message77(77),apmask(128),cw(128) + integer*1 hbits(152),hbits1(152),hbits3(152) + integer*1 s12(12) + integer graymap(0:3) + integer ip(1) + logical unpk77_success + logical one(0:511,0:7) ! 256 4-symbol sequences, 8 bits + data s12/1,1,1,2,2,2,2,2,2,1,1,1/ + data icos4/0,1,3,2/ + data graymap/0,1,3,2/ + save one + + fs=12000.0/NDOWN !Sample rate + dt=1/fs !Sample interval after downsample (s) + tt=NSPS*dt !Duration of "itone" symbols (s) + baud=1.0/tt !Keying rate for "itone" symbols (baud) + txt=NZ*dt !Transmission length (s) + twopi=8.0*atan(1.0) + h=1.0 !h=0.8 seems to be optimum for AWGN sensitivity (not for fading) + + one=.false. + do i=0,255 + do j=0,7 + if(iand(i,2**j).ne.0) one(i,j)=.true. + enddo + enddo + + nargs=iargc() + if(nargs.lt.1) then + print*,'Usage: ft4d [-a ] [-f fMHz] file1 [file2 ...]' + go to 999 + endif + iarg=1 + data_dir="." + call getarg(iarg,arg) + if(arg(1:2).eq.'-a') then + call getarg(iarg+1,data_dir) + iarg=iarg+2 + endif + call getarg(iarg,arg) + if(arg(1:2).eq.'-f') then + call getarg(iarg+1,arg) + read(arg,*) fMHz + iarg=iarg+2 + endif + ncoh=1 + + do ifile=iarg,nargs + call getarg(ifile,infile) + j2=index(infile,'.wav') + open(10,file=infile,status='old',access='stream') + read(10,end=999) ihdr,iwave + read(infile(j2-4:j2-1),*) nutc + datetime=infile(j2-11:j2-1) + close(10) + candidate=0.0 + ncand=0 + + nfqso=1500 + nfa=500 + nfb=2700 + syncmin=1.0 + maxcand=100 +! call syncft4(iwave,nfa,nfb,syncmin,nfqso,maxcand,s,candidate,ncand,sbase) + + call getcandidates4(iwave,375.0,3000.0,0.2,2200.0,100,savg,candidate,ncand,sbase) + ndecodes=0 + do icand=1,ncand + f0=candidate(1,icand)-1.5*37.5 + xsnr=1.0 + if( f0.le.375.0 .or. f0.ge.(5000.0-375.0) ) cycle + call ft4_downsample(iwave,f0,cd2) ! downsample from 320 Sa/Symbol to 20 Sa/Symbol + sum2=sum(cd2*conjg(cd2))/(20.0*76) + if(sum2.gt.0.0) cd2=cd2/sqrt(sum2) + +! 750 samples/second here + ibest=-1 + smax=-99. + dfbest=-1. + do idf=-90,+90,5 + df=idf + a=0. + a(1)=df + ctwk=1. + call twkfreq1(ctwk,80,fs,a,ctwk2) + do istart=0,315 + call sync4d(cd2,istart,ctwk2,1,sync) + if(sync.gt.smax) then + smax=sync + ibest=istart + dfbest=df + endif + enddo + enddo + + f0=f0+dfbest +!f0=1443.75 + call ft4_downsample(iwave,f0,cb) ! downsample from 320s/Symbol to 20s/Symbol + sum2=sum(abs(cb)**2)/(20.0*76) + if(sum2.gt.0.0) cb=cb/sqrt(sum2) +!ibest=208 + cd=cb(ibest:ibest+76*20-1) + do k=1,NN + i1=(k-1)*20 + csymb=cd(i1:i1+19) + call four2a(csymb,20,1,-1,1) + cs(0:3,k)=csymb(1:4)/1e2 + s4(0:3,k)=abs(csymb(1:4)) + enddo + +! sync quality check + is1=0 + is2=0 + is3=0 + do k=1,4 + ip=maxloc(s4(:,k)) + if(icos4(k-1).eq.(ip(1)-1)) is1=is1+1 + ip=maxloc(s4(:,k+36)) + if(icos4(k-1).eq.(ip(1)-1)) is2=is2+1 + ip=maxloc(s4(:,k+72)) + if(icos4(k-1).eq.(ip(1)-1)) is3=is3+1 + enddo +! hard sync sum - max is 12 + nsync=is1+is2+is3 + + do nseq=1,3 + if(nseq.eq.1) nsym=1 + if(nseq.eq.2) nsym=2 + if(nseq.eq.3) nsym=4 + nt=2**(2*nsym) + do ks=1,76,nsym + amax=-1.0 + do i=0,nt-1 + i1=i/64 + i2=iand(i,63)/16 + i3=iand(i,15)/4 + i4=iand(i,3) + if(nsym.eq.1) then + s2(i)=abs(cs(graymap(i4),ks)) + elseif(nsym.eq.2) then + s2(i)=abs(cs(graymap(i3),ks)+cs(graymap(i4),ks+1)) + elseif(nsym.eq.4) then + s2(i)=abs(cs(graymap(i1),ks ) + & + cs(graymap(i2),ks+1) + & + cs(graymap(i3),ks+2) + & + cs(graymap(i4),ks+3) & + ) + else + print*,"Error - nsym must be 1, 2, or 4." + endif + enddo + ipt=1+(ks-1)*2 + if(nsym.eq.1) ibmax=1 + if(nsym.eq.2) ibmax=3 + if(nsym.eq.4) ibmax=7 + do ib=0,ibmax + bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - & + maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib)) + if(ipt+ib .gt.152) cycle + if(nsym.eq.1) then + bmeta(ipt+ib)=bm + elseif(nsym.eq.2) then + bmetb(ipt+ib)=bm + elseif(nsym.eq.4) then + bmetc(ipt+ib)=bm + endif + enddo + enddo + enddo + + call normalizebmet(bmeta,152) + call normalizebmet(bmetb,152) + call normalizebmet(bmetc,152) + + hbits=0 + where(bmeta.ge.0) hbits=1 + ns1=count(hbits( 1: 8).eq.(/0,0,0,1,1,0,1,1/)) + ns2=count(hbits( 73: 80).eq.(/0,0,0,1,1,0,1,1/)) + ns3=count(hbits(145:152).eq.(/0,0,0,1,1,0,1,1/)) + nsync_qual=ns1+ns2+ns3 + + sigma=0.7 + llra(1:64)=bmeta(9:72) + llra(65:128)=bmeta(81:144) + llra=2*llra/sigma**2 + llrb(1:64)=bmetb(9:72) + llrb(65:128)=bmetb(81:144) + llrb=2*llrb/sigma**2 + llrc(1:64)=bmetc(9:72) + llrc(65:128)=bmetc(81:144) + llrc=2*llrc/sigma**2 + + do isd=1,3 + if(isd.eq.1) llr=llra + if(isd.eq.2) llr=llrb + if(isd.eq.3) llr=llrc + apmask=0 + max_iterations=40 + do ibias=0,0 + llr2=llr + if(ibias.eq.1) llr2=llr+0.4 + if(ibias.eq.2) llr2=llr-0.4 + call bpdecode128_90(llr2,apmask,max_iterations,message77,cw,nharderror,niterations) + if(nharderror.ge.0) exit + enddo + if(sum(message77).eq.0) cycle + if( nharderror.ge.0 ) then + write(c77,'(77i1)') message77(1:77) + call unpack77(c77,1,message,unpk77_success) + idupe=0 + do i=1,ndecodes + if(decodes(i).eq.message) idupe=1 + enddo + if(idupe.eq.1) cycle + ndecodes=ndecodes+1 + decodes(ndecodes)=message + nsnr=nint(xsnr) + write(*,1212) datetime(8:11),nsnr,ibest/750.0,f0,message,'*',nharderror,nsync_qual,isd,niterations +1212 format(a4,i4,2x,f5.3,f11.1,2x,a22,a1,i5,i5,i5,i5) + endif + enddo ! sequence estimation + enddo !candidate list + enddo !files + + write(*,1120) +1120 format("") + +999 end program ft4d + +subroutine getbitmetric(ib,ps,ns,xmet) + real ps(0:ns-1) + xm1=0 + xm0=0 + do i=0,ns-1 + if( iand(i/ib,1) .eq. 1 .and. ps(i) .gt. xm1 ) xm1=ps(i) + if( iand(i/ib,1) .eq. 0 .and. ps(i) .gt. xm0 ) xm0=ps(i) + enddo + xmet=xm1-xm0 + return +end subroutine getbitmetric + +subroutine downsample4(ci,f0,co) + parameter(NI=144*160,NH=NI/2,NO=NI/16) ! downsample from 200 samples per symbol to 10 + complex ci(0:NI-1),ct(0:NI-1) + complex co(0:NO-1) + fs=12000.0 + df=fs/NI + ct=ci + call four2a(ct,NI,1,-1,1) !c2c FFT to freq domain + i0=nint(f0/df) + ct=cshift(ct,i0) + co=0.0 + co(0)=ct(0) + b=8.0 + do i=1,NO/2 + arg=(i*df/b)**2 + filt=exp(-arg) + co(i)=ct(i)*filt + co(NO-i)=ct(NI-i)*filt + enddo + co=co/NO + call four2a(co,NO,1,1,1) !c2c FFT back to time domain + return +end subroutine downsample4 + +subroutine ft4_downsample(iwave,f0,c) + +! Input: i*2 data in iwave() at sample rate 12000 Hz +! Output: Complex data in c(), sampled at 1200 Hz + + include 'ft4_params.f90' + parameter (NFFT2=NMAX/16) + integer*2 iwave(NMAX) + complex c(0:NMAX/16-1) + complex c1(0:NFFT2-1) + complex cx(0:NMAX/2) + real x(NMAX) + equivalence (x,cx) + + BW=6.0*75 + df=12000.0/NMAX + x=iwave + call four2a(x,NMAX,1,-1,0) !r2c FFT to freq domain + ibw=nint(BW/df) + i0=nint(f0/df) + c1=0. + c1(0)=cx(i0) + do i=1,NFFT2/2 + arg=(i-1)*df/bw + win=exp(-arg*arg) + c1(i)=cx(i0+i)*win + c1(NFFT2-i)=cx(i0-i)*win + enddo + c1=c1/NFFT2 + call four2a(c1,NFFT2,1,1,1) !c2c FFT back to time domain + c=c1(0:NMAX/16-1) + return +end subroutine ft4_downsample + diff --git a/lib/fsk4hf/genft2.f90 b/lib/fsk4hf/genft2.f90 new file mode 100644 index 000000000..2eb36bccc --- /dev/null +++ b/lib/fsk4hf/genft2.f90 @@ -0,0 +1,86 @@ +subroutine genft2(msg0,ichk,msgsent,i4tone,itype) +! s8 + 48bits + s8 + 80 bits = 144 bits (72ms message duration) +! +! Encode an MSK144 message +! Input: +! - msg0 requested message to be transmitted +! - ichk if ichk=1, return only msgsent +! if ichk.ge.10000, set imsg=ichk-10000 for short msg +! - msgsent message as it will be decoded +! - i4tone array of audio tone values, 0 or 1 +! - itype message type +! 1 = 77 bit message +! 7 = 16 bit message " Rpt" + + use iso_c_binding, only: c_loc,c_size_t + use packjt77 + character*37 msg0 + character*37 message !Message to be generated + character*37 msgsent !Message as it will be received + character*77 c77 + integer*4 i4tone(144) + integer*1 codeword(128) + integer*1 msgbits(77) + integer*1 bitseq(144) !Tone #s, data and sync (values 0-1) + integer*1 s16(16) + real*8 xi(864),xq(864),pi,twopi + data s16/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0/ + equivalence (ihash,i1hash) + logical unpk77_success + + nsym=128 + pi=4.0*atan(1.0) + twopi=8.*atan(1.0) + + message(1:37)=' ' + itype=1 + if(msg0(1:1).eq.'@') then !Generate a fixed tone + read(msg0(2:5),*,end=1,err=1) nfreq !at specified frequency + go to 2 +1 nfreq=1000 +2 i4tone(1)=nfreq + else + message=msg0 + + do i=1, 37 + if(ichar(message(i:i)).eq.0) then + message(i:37)=' ' + exit + endif + enddo + do i=1,37 !Strip leading blanks + if(message(1:1).ne.' ') exit + message=message(i+1:) + enddo + + if(message(1:1).eq.'<') then + i2=index(message,'>') + i1=0 + if(i2.gt.0) i1=index(message(1:i2),' ') + if(i1.gt.0) then + call genmsk40(message,msgsent,ichk,i4tone,itype) + if(itype.lt.0) go to 999 + i4tone(41)=-40 + go to 999 + endif + endif + + i3=-1 + n3=-1 + call pack77(message,i3,n3,c77) + call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent + + if(ichk.eq.1) go to 999 + read(c77,"(77i1)") msgbits + call encode_128_90(msgbits,codeword) + +!Create 144-bit channel vector: + bitseq=0 + bitseq(1:16)=s16 + bitseq(17:144)=codeword + + i4tone=bitseq + endif + +999 return +end subroutine genft2 diff --git a/lib/fsk4hf/getcandidates2.f90 b/lib/fsk4hf/getcandidates2.f90 new file mode 100644 index 000000000..3aa841c83 --- /dev/null +++ b/lib/fsk4hf/getcandidates2.f90 @@ -0,0 +1,63 @@ +subroutine getcandidates2(id,fa,fb,syncmin,nfqso,maxcand,savg,candidate, & + ncand,sbase) + +! For now, hardwired to find the largest peak in the average spectrum + + include 'ft2_params.f90' + real s(NH1,NHSYM) + real savg(NH1),savsm(NH1) + real sbase(NH1) + real x(NFFT1) + complex cx(0:NH1) + real candidate(3,maxcand) + integer*2 id(NMAX) + integer*1 s8(8) + integer indx(NH1) + data s8/0,1,1,1,0,0,1,0/ + equivalence (x,cx) + +! Compute symbol spectra, stepping by NSTEP steps. + savg=0. + tstep=NSTEP/12000.0 + df=12000.0/NFFT1 !3.125 Hz + fac=1.0/300.0 + do j=1,NHSYM + ia=(j-1)*NSTEP + 1 + ib=ia+NSPS-1 + x(1:NSPS)=fac*id(ia:ib) + x(NSPS+1:)=0. + call four2a(x,NFFT1,1,-1,0) !r2c FFT + do i=1,NH1 + s(i,j)=real(cx(i))**2 + aimag(cx(i))**2 + enddo + savg=savg + s(1:NH1,j) !Average spectrum + enddo + savsm=0. + do i=2,NH1-1 + savsm(i)=sum(savg(i-1:i+1))/3. + enddo + + nfa=fa/df + nfb=fb/df + np=nfb-nfa+1 + indx=0 + call indexx(savsm(nfa:nfb),np,indx) + xn=savsm(nfa+indx(nint(0.3*np))) + savsm=savsm/xn + imax=-1 + xmax=-99. + do i=2,NH1-1 + if(savsm(i).gt.savsm(i-1).and. & + savsm(i).gt.savsm(i+1).and. & + savsm(i).gt.xmax) then + xmax=savsm(i) + imax=i + endif + enddo + f0=imax*df + if(xmax.gt.1.2) then + ncand=ncand+1 + candidate(1,ncand)=f0 + endif +return +end subroutine getcandidates2 diff --git a/lib/fsk4hf/mskhfsim.f90 b/lib/fsk4hf/mskhfsim.f90 deleted file mode 100644 index 86140e1ce..000000000 --- a/lib/fsk4hf/mskhfsim.f90 +++ /dev/null @@ -1,194 +0,0 @@ -program msksim - -! Simulate characteristics of a potential "MSK10" mode using LDPC (168,84) -! code, OQPDK modulation, and 30 s T/R sequences. - -! Reception and Demodulation algorithm: -! 1. Compute coarse spectrum; find fc1 = approx carrier freq -! 2. Mix from fc1 to 0; LPF at +/- 0.75*R -! 3. Square, FFT; find peaks near -R/2 and +R/2 to get fc2 -! 4. Mix from fc2 to 0 -! 5. Fit cb13 (central part of csync) to c -> lag, phase -! 6. Fit complex ploynomial for channel equalization -! 7. Get soft bits from equalized data - - parameter (KK=84) !Information bits (72 + CRC12) - parameter (ND=168) !Data symbols: LDPC (168,84), r=1/2 - parameter (NS=65) !Sync symbols (2 x 26 + Barker 13) - parameter (NR=3) !Ramp up/down - parameter (NN=NR+NS+ND) !Total symbols (236) - parameter (NSPS=1152/72) !Samples per MSK symbol (16) - parameter (N2=2*NSPS) !Samples per OQPSK symbol (32) - parameter (N13=13*N2) !Samples in central sync vector (416) - parameter (NZ=NSPS*NN) !Samples in baseband waveform (3776) - parameter (NFFT1=4*NSPS,NH1=NFFT1/2) - - character*8 arg - complex cbb(0:NZ-1) !Complex baseband waveform - complex csync(0:NZ-1) !Sync symbols only, from cbb - complex cb13(0:N13-1) !Barker 13 waveform - complex c(0:NZ-1) !Complex waveform - complex c0(0:NZ-1) !Complex waveform - complex zz(NS+ND) !Complex symbol values (intermediate) - complex z - real xnoise(0:NZ-1) !Generated random noise - real ynoise(0:NZ-1) !Generated random noise - real rxdata(ND),llr(ND) !Soft symbols - real pp(2*NSPS) !Shaped pulse for OQPSK - real a(5) !For twkfreq1 - real aa(20),bb(20) !Fitted polyco's - integer id(NS+ND) !NRZ values (+/-1) for Sync and Data - integer ierror(NS+ND) - integer icw(NN) - integer*1 msgbits(KK),decoded(KK),apmask(ND),cw(ND) -! integer*1 codeword(ND) - data msgbits/0,0,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1, & - 1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,0,1,1,0,1,1, & - 1,1,0,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0/ - - nargs=iargc() - if(nargs.ne.6) then - print*,'Usage: mskhfsim f0(Hz) delay(ms) fspread(Hz) maxn iters snr(dB)' - print*,'Example: mskhfsim 0 0 0 5 10 -20' - print*,'Set snr=0 to cycle through a range' - go to 999 - endif - call getarg(1,arg) - read(arg,*) f0 !Generated carrier frequency - call getarg(2,arg) - read(arg,*) delay !Delta_t (ms) for Watterson model - call getarg(3,arg) - read(arg,*) fspread !Fspread (Hz) for Watterson model - call getarg(4,arg) - read(arg,*) maxn !Max nterms for polyfit - call getarg(5,arg) - read(arg,*) iters !Iterations at each SNR - call getarg(6,arg) - read(arg,*) snrdb !Specified SNR_2500 - - twopi=8.0*atan(1.0) - fs=12000.0/72.0 !Sample rate = 166.6666667 Hz - dt=1.0/fs !Sample interval (s) - tt=NSPS*dt !Duration of "itone" symbols (s) - ts=2*NSPS*dt !Duration of OQPSK symbols (s) - baud=1.0/tt !Keying rate for "itone" symbols (baud) - txt=NZ*dt !Transmission length (s) - bandwidth_ratio=2500.0/(fs/2.0) - write(*,1000) f0,delay,fspread,maxn,iters,baud,3*baud,txt -1000 format('f0:',f5.1,' Delay:',f4.1,' fSpread:',f5.2,' maxn:',i3, & - ' Iters:',i6/'Baud:',f7.3,' BW:',f5.1,' TxT:',f5.1,f5.2/) - write(*,1004) -1004 format(/' SNR err ber fer fsigma'/37('-')) - - do i=1,N2 !Half-sine pulse shape - pp(i)=sin(0.5*(i-1)*twopi/(2*NSPS)) - enddo - - call genmskhf(msgbits,id,icw,cbb,csync)!Generate baseband waveform and csync - cb13=csync(1680:2095) !Copy the Barker 13 waveform - a=0. - a(1)=f0 - call twkfreq1(cbb,NZ,fs,a,cbb) !Mix to specified frequency - - isna=-10 - isnb=-30 - if(snrdb.ne.0.0) then - isna=nint(snrdb) - isnb=isna - endif - do isnr=isna,isnb,-1 !Loop over SNR range - snrdb=isnr - sig=sqrt(bandwidth_ratio) * 10.0**(0.05*snrdb) - if(snrdb.gt.90.0) sig=1.0 - nhard=0 - nhardsync=0 - nfe=0 - sqf=0. - do iter=1,iters !Loop over requested iterations - c=cbb - if(delay.ne.0.0 .or. fspread.ne.0.0) then - call watterson(c,NZ,fs,delay,fspread) - endif - c=sig*c !Scale to requested SNR - if(snrdb.lt.90) then - do i=0,NZ-1 !Generate gaussian noise - xnoise(i)=gran() - ynoise(i)=gran() - enddo - c=c + cmplx(xnoise,ynoise) !Add AWGN noise - endif - - call getfc1(c,fc1) !First approx for freq - call getfc2(c,csync,fc1,fc2,fc3) !Refined freq - sqf=sqf + (fc1+fc2-f0)**2 - -!NB: Measured performance is about equally good using fc2 or fc3 here: - a(1)=-(fc1+fc2) - a(2:5)=0. - call twkfreq1(c,NZ,fs,a,c) !Mix c down by fc1+fc2 - -! The following may not be necessary? -! z=sum(c(1680:2095)*cb13)/208.0 !Get phase from Barker 13 vector -! z0=z/abs(z) -! c=c*conjg(z0) - -!---------------------------------------------------------------- DT -! Not presently used: - amax=0. - jpk=0 - do j=-20*NSPS,20*NSPS !Get jpk - z=sum(c(1680+j:2095+j)*cb13)/208.0 - if(abs(z).gt.amax) then - amax=abs(z) - jpk=j - endif - enddo - xdt=jpk/fs - - nterms=maxn - c0=c - do itry=1,10 - idf=itry/2 - if(mod(itry,2).eq.0) idf=-idf - nhard0=0 - nhardsync0=0 - ifer=1 - a(1)=idf*0.01 - a(2:5)=0. - call twkfreq1(c0,NZ,fs,a,c) !Mix c0 into c - call cpolyfit(c,pp,id,maxn,aa,bb,zz,nhs) - call msksoftsym(zz,aa,bb,id,nterms,ierror,rxdata,nhard0,nhardsync0) - if(nhardsync0.gt.12) cycle - rxav=sum(rxdata)/ND - rx2av=sum(rxdata*rxdata)/ND - rxsig=sqrt(rx2av-rxav*rxav) - rxdata=rxdata/rxsig - ss=0.84 - llr=2.0*rxdata/(ss*ss) - apmask=0 - max_iterations=40 - ifer=0 - call bpdecode168(llr,apmask,max_iterations,decoded,niterations,cw) - nbadcrc=0 - if(niterations.ge.0) call chkcrc12(decoded,nbadcrc) - if(niterations.lt.0 .or. count(msgbits.ne.decoded).gt.0 .or. & - nbadcrc.ne.0) ifer=1 -! if(ifer.eq.0) write(67,1301) snrdb,itry,idf,niterations, & -! nhardsync0,nhard0 -!1301 format(f6.1,5i6) - if(ifer.eq.0) exit - enddo !Freq dither loop - nhard=nhard+nhard0 - nhardsync=nharsdync+nhardsync0 - nfe=nfe+ifer - enddo - - fsigma=sqrt(sqf/iters) - ber=float(nhard)/((NS+ND)*iters) - fer=float(nfe)/iters - write(*,1050) snrdb,nhard,ber,fer,fsigma -! write(60,1050) snrdb,nhard,ber,fer,fsigma -1050 format(f6.1,i7,f8.4,f7.3,f8.2) - enddo - -999 end program msksim diff --git a/lib/fsk4hf/spb.m b/lib/fsk4hf/spb.m index ed1761925..9bb164506 100644 --- a/lib/fsk4hf/spb.m +++ b/lib/fsk4hf/spb.m @@ -70,14 +70,14 @@ endfunction # M-ary PSK Block Coded Modulation," Igal Sason and Gil Weichman, # doi: 10.1109/EEEI.2006.321097 #------------------------------------------------------------------------------- -N=174 -K=75 +N=128 +K=90 R=K/N delta=0.01; [ths,fval,info,output]=fzero(@f1,[delta,pi/2-delta], optimset ("jacobian", "off")); -for ebnodb=-6:0.5:4 +for ebnodb=-3:0.5:4 ebno=10^(ebnodb/10.0); esno=ebno*R; A=sqrt(2*esno); diff --git a/lib/fsk4hf/spb_128_90.dat b/lib/fsk4hf/spb_128_90.dat new file mode 100644 index 000000000..9e32e28e9 --- /dev/null +++ b/lib/fsk4hf/spb_128_90.dat @@ -0,0 +1,19 @@ +N = 128 +K = 90 +R = 0.70312 +-3.000000 0.000341 +-2.500000 0.001513 +-2.000000 0.006049 +-1.500000 0.021280 +-1.000000 0.064283 +-0.500000 0.162755 +0.000000 0.338430 +0.500000 0.571867 +1.000000 0.791634 +1.500000 0.930284 +2.000000 0.985385 +2.500000 0.998258 +3.000000 0.999893 +3.500000 0.999997 +4.000000 1.000000 + diff --git a/lib/ft2/cdatetime.f90 b/lib/ft2/cdatetime.f90 new file mode 100644 index 000000000..33deaf30a --- /dev/null +++ b/lib/ft2/cdatetime.f90 @@ -0,0 +1,6 @@ +character*17 function cdatetime() + character cdate*8,ctime*10 + call date_and_time(cdate,ctime) + cdatetime=cdate(3:8)//'_'//ctime + return +end function cdatetime diff --git a/lib/ft2/ft2.f90 b/lib/ft2/ft2.f90 new file mode 100644 index 000000000..e5c389f90 --- /dev/null +++ b/lib/ft2/ft2.f90 @@ -0,0 +1,279 @@ +program ft2 + + use packjt77 + include 'gcom1.f90' + integer ft2audio,ptt + logical allok + character*20 pttport + character*8 arg + character*80 fname + integer*2 id2(30000) + + open(12,file='all_ft2.txt',status='unknown',position='append') + nargs=iargc() + if(nargs.eq.1) then + call getarg(1,fname) + open(10,file=fname,status='old',access='stream') + read(10) id2(1:22) !Read (and ignore) the header + read(10) id2 !Read the Rx data + close(10) + call ft2_decode(fname(1:17),nfqso,id2,ndecodes,mycall,hiscall,nrx) + go to 999 + endif + + allok=.true. +! Get home-station details + open(10,file='ft2.ini',status='old',err=1) + go to 2 +1 print*,'Cannot open ft2.ini' + allok=.false. +2 read(10,*,err=3) mycall,mygrid,ndevin,ndevout,pttport,exch + go to 4 +3 print*,'Error reading ft2.ini' + allok=.false. +4 if(index(pttport,'/').lt.1) read(pttport,*) nport + hiscall=' ' + hiscall_next=' ' + idevin=ndevin + idevout=ndevout + call padevsub(idevin,idevout) + if(idevin.ne.ndevin .or. idevout.ne.ndevout) allok=.false. + i1=0 + i1=ptt(nport,1,1,iptt) + i1=ptt(nport,1,0,iptt) + if(i1.lt.0 .and. nport.ne.0) allok=.false. + if(.not.allok) then + write(*,"('Please fix setup error(s) and restart.')") + go to 999 + endif + + nright=1 + iwrite=0 + iwave=0 + nwave=NTZ + nfsample=12000 + ngo=1 + npabuf=1152 + ntxok=0 + ntransmitting=0 + tx_once=.false. + snrdb=99.0 + txmsg='CQ K1JT FN20' + ltx=.false. + lrx=.false. + autoseq=.false. + QSO_in_progress=.false. + ntxed=0 + + if(nargs.eq.3) then + call getarg(1,txmsg) + call getarg(2,arg) + read(arg,*) f0 + call getarg(3,arg) + read(arg,*) snrdb + tx_once=.true. + ftx=1500.0 + call transmit(-1,ftx,iptt) + snrdb=99.0 + endif + +! Start the audio streams + ierr=ft2audio(idevin,idevout,npabuf,nright,y1,y2,NRING,iwrite,itx, & + iwave,nwave+3*1152,nfsample,nTxOK,nTransmitting,ngo) + if(ierr.ne.0) then + print*,'Error',ierr,' starting audio input and/or output.' + endif + +999 end program ft2 + +subroutine update(total_time,ic1,ic2) + + use wavhdr + type(hdr) h + real*8 total_time + integer*8 count0,count1,clkfreq + integer ptt + integer*2 id(30000) + logical transmitted,level,ok + character*70 line + character cdatetime*17,fname*17,mode*8,band*6 + include 'gcom1.f90' + data nt0/-1/,transmitted/.false./,snr/-99.0/ + data level/.false./ + save nt0,transmitted,level,snr,iptt + + if(ic1.ne.0 .or. ic2.ne.0) then + if(ic1.eq.27 .and. ic2.eq.0) ngo=0 !ESC + if(nTxOK.eq.0 .and. ntransmitting.eq.0) then + nfunc=0 + if(ic1.eq.0 .and. ic2.eq.59) nfunc=1 !F1 + if(ic1.eq.0 .and. ic2.eq.60) nfunc=2 !F2 + if(ic1.eq.0 .and. ic2.eq.61) nfunc=3 !F3 + if(ic1.eq.0 .and. ic2.eq.62) nfunc=4 !F4 + if(ic1.eq.0 .and. ic2.eq.63) nfunc=5 !F5 + if(nfunc.eq.1 .or. (nfunc.ge.2 .and. hiscall.ne.' ')) then + ftx=1500.0 + call transmit(nfunc,ftx,iptt) + endif + endif + if(ic1.eq.13 .and. ic2.eq.0) hiscall=hiscall_next + if((ic1.eq.97 .or. ic1.eq.65) .and. ic2.eq.0) autoseq=.not.autoseq + if((ic1.eq.108 .or. ic1.eq.76) .and. ic2.eq.0) level=.not.level + endif + + if(ntransmitting.eq.1) transmitted=.true. + if(transmitted .and. ntransmitting.eq.0) then + i1=0 + if(iptt.eq.1 .and. nport.gt.0) i1=ptt(nport,0,1,iptt) + if(tx_once .and. transmitted) stop + transmitted=.false. + endif + + nt=2*total_time + if(nt.gt.nt0 .or. ic1.ne.0 .or. ic2.ne.0) then + if(level) then +! Measure and display the average level of signal plus noise in past 0.5 s + k=iwrite-6000 + if(k.lt.1) k=k+NRING + sq=0. + do i=1,6000 + k=k+1 + if(k.gt.NRING) k=k-NRING + x=y1(k) + sq=sq + x*x + enddo + sigdb=0. + if(sq.gt.0.0) sigdb=db(sq/6000.0) + n=sigdb + if(n.lt.1) n=1 + if(n.gt.70) n=70 + line=' ' + line(n:n)='*' + write(*,1030) sigdb,ntxed,autoseq,QSO_in_progress,(line(i:i),i=1,n) +1030 format(f4.1,i3,2L2,1x,70a1) +! write(*,1020) nt,total_time,iwrite,itx,ntxok,ntransmitting,ndecodes, & +! snr,sigdb,line +!1020 format(i6,f9.3,i10,i6,3i3,f6.0,f6.1,1x,a30) + endif + k=iwrite-30000 + if(k.lt.1) k=k+NRING + do i=1,30000 + k=k+1 + if(k.gt.NRING) k=k-NRING + id(i)=y1(k) + enddo + nutc=0 + nfqso=1500 + ndecodes=0 + if(maxval(abs(id)).gt.0) then + call system_clock(count0,clkfreq) + nrx=-1 + call ft2_decode(cdatetime(),nfqso,id,ndecodes,mycall,hiscall,nrx) + call system_clock(count1,clkfreq) +! tdecode=float(count1-count0)/float(clkfreq) + + if(ndecodes.ge.1) then + fMHz=7.074 + mode='FT2' + nsubmode=1 + ntrperiod=0 + h=default_header(12000,30000) + k=0 + do i=1,250 + sq=0 + do n=1,120 + k=k+1 + x=id(k) + sq=sq + x*x + enddo + write(43,3043) i,0.01*i,1.e-4*sq +3043 format(i7,f12.6,f12.3) + enddo + call set_wsjtx_wav_params(fMHz,mode,nsubmode,ntrperiod,id) + band="" + mode="" + nsubmode=-1 + ntrperiod=-1 + call get_wsjtx_wav_params(id,band,mode,nsubmode,ntrperiod,ok) +! write(*,1010) band,ntrperiod,mode,char(ichar('A')-1+id(3)) +!1010 format('Band: ',a6,' T/R period:',i4,' Mode: ',a8,1x,a1) + + fname=cdatetime() + fname(14:17)='.wav' + open(13,file=fname,status='unknown',access='stream') + write(13) h,id + close(13) + endif + if(autoseq .and.nrx.eq.2) QSO_in_progress=.true. + if(autoseq .and. QSO_in_progress .and. nrx.ge.1 .and. nrx.le.4) then + lrx(nrx)=.true. + ftx=1500.0 + if(ntxed.eq.1) then + if(nrx.eq.2) then + call transmit(3,ftx,iptt) + else + call transmit(1,ftx,iptt) + endif + endif + if(ntxed.eq.2) then + if(nrx.eq.3) then + call transmit(4,ftx,iptt) + QSO_in_progress=.false. + write(*,1032) +1032 format('QSO complete: S+P side') + else + call transmit(2,ftx,iptt) + endif + endif + if(ntxed.eq.3) then + if(nrx.eq.4) then + QSO_in_progress=.false. + write(*,1034) +1034 format('QSO complete: CQ side') + else + call transmit(3,ftx,iptt) + endif + endif + endif + endif + nt0=nt + endif + + return +end subroutine update + +character*17 function cdatetime() + character cdate*8,ctime*10 + call date_and_time(cdate,ctime) + cdatetime=cdate(3:8)//'_'//ctime + return +end function cdatetime + +subroutine transmit(nfunc,ftx,iptt) + include 'gcom1.f90' + character*17 cdatetime + integer ptt + + if(nTxOK.eq.1) return + + if(nfunc.eq.1) txmsg='CQ '//trim(mycall)//' '//mygrid + if(nfunc.eq.2) txmsg=trim(hiscall)//' '//trim(mycall)// & + ' 559 '//trim(exch) + if(nfunc.eq.3) txmsg=trim(hiscall)//' '//trim(mycall)// & + ' R 559 '//trim(exch) + if(nfunc.eq.4) txmsg=trim(hiscall)//' '//trim(mycall)//' RR73' + if(nfunc.eq.5) txmsg='TNX 73 GL' + call ft2_iwave(txmsg,ftx,snrdb,iwave) + iwave(23041:)=0 + i1=ptt(nport,1,1,iptt) + ntxok=1 + n=len(trim(txmsg)) + write(*,1010) cdatetime(),0,0.0,nint(ftx),(txmsg(i:i),i=1,n) + write(12,1010) cdatetime(),0,0.0,nint(ftx),(txmsg(i:i),i=1,n) +1010 format(a17,i4,f6.2,i5,' Tx ',37a1) + if(nfunc.ge.1 .and. nfunc.le.4) ntxed=nfunc + if(nfunc.ge.1 .and. nfunc.le.5) ltx(nfunc)=.true. + if(nfunc.eq.2 .or. nfunc.eq.3) QSO_in_progress=.true. + + return +end subroutine transmit diff --git a/lib/ft2/ft2.ini b/lib/ft2/ft2.ini new file mode 100644 index 000000000..d66770d17 --- /dev/null +++ b/lib/ft2/ft2.ini @@ -0,0 +1,2 @@ +K1JT FN20 1 5 0 NJ +MyCall MyGrid AudioIn AudioOut PTTport Exch diff --git a/lib/ft2/ft2_decode.f90 b/lib/ft2/ft2_decode.f90 new file mode 100644 index 000000000..1d1bb6a53 --- /dev/null +++ b/lib/ft2/ft2_decode.f90 @@ -0,0 +1,298 @@ +subroutine ft2_decode(cdatetime0,nfqso,iwave,ndecodes,mycall,hiscall,nrx,line) + + use crc + use packjt77 + include 'ft2_params.f90' + character message*37,c77*77 + character*61 line + character*37 decodes(100) + character*120 data_dir + character*17 cdatetime0,cdatetime + character*6 mycall,hiscall,hhmmss + complex c2(0:NMAX/16-1) !Complex waveform + complex cb(0:NMAX/16-1) + complex cd(0:144*10-1) !Complex waveform + complex c1(0:9),c0(0:9) + complex ccor(0:1,144) + complex csum,cterm,cc0,cc1,csync1 + real*8 fMHz + + real a(5) + real rxdata(128),llr(128) !Soft symbols + real llr2(128) + real sbits(144),sbits1(144),sbits3(144) + real ps(0:8191),psbest(0:8191) + real candidate(3,100) + real savg(NH1) + integer*2 iwave(NMAX) !Generated full-length waveform + integer*1 message77(77),apmask(128),cw(128) + integer*1 hbits(144),hbits1(144),hbits3(144) + integer*1 s16(16) + logical unpk77_success + data s16/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0/ + + hhmmss=cdatetime0(8:13) + fs=12000.0/NDOWN !Sample rate + dt=1/fs !Sample interval after downsample (s) + tt=NSPS*dt !Duration of "itone" symbols (s) + baud=1.0/tt !Keying rate for "itone" symbols (baud) + txt=NZ*dt !Transmission length (s) + twopi=8.0*atan(1.0) + h=0.8 !h=0.8 seems to be optimum for AWGN sensitivity (not for fading) + + dphi=twopi/2*baud*h*dt*16 ! dt*16 is samp interval after downsample + dphi0=-1*dphi + dphi1=+1*dphi + phi0=0.0 + phi1=0.0 + do i=0,9 + c1(i)=cmplx(cos(phi1),sin(phi1)) + c0(i)=cmplx(cos(phi0),sin(phi0)) + phi1=mod(phi1+dphi1,twopi) + phi0=mod(phi0+dphi0,twopi) + enddo + the=twopi*h/2.0 + cc1=cmplx(cos(the),-sin(the)) + cc0=cmplx(cos(the),sin(the)) + + data_dir="." + fMHz=7.074 + ncoh=1 + candidate=0.0 + ncand=0 + fa=375.0 + fb=3000.0 + syncmin=0.2 + maxcand=100 + nfqso=-1 + call getcandidates2a(iwave,fa,fb,maxcand,savg,candidate,ncand) + ndecodes=0 + do icand=1,ncand + f0=candidate(1,icand) + if( f0.le.375.0 .or. f0.ge.(5000.0-375.0) ) cycle + call ft2_downsample(iwave,f0,c2) ! downsample from 160s/Symbol to 10s/Symbol +! 750 samples/second here + ibest=-1 + sybest=-99. + dfbest=-1. +!### do if=-15,+15 + do if=-30,30 + df=if + a=0. + a(1)=-df + call twkfreq1(c2,NMAX/16,fs,a,cb) + do is=0,374 !DT search range is 0 - 0.5 s + csync1=0. + cterm=1 + do ib=1,16 + i1=(ib-1)*10+is + i2=i1+136*10 + if(s16(ib).eq.1) then + csync1=csync1+sum(cb(i1:i1+9)*conjg(c1(0:9)))*cterm + cterm=cterm*cc1 + else + csync1=csync1+sum(cb(i1:i1+9)*conjg(c0(0:9)))*cterm + cterm=cterm*cc0 + endif + enddo + if(abs(csync1).gt.sybest) then + ibest=is + sybest=abs(csync1) + dfbest=df + endif + enddo + enddo + + a=0. + a(1)=-dfbest + call twkfreq1(c2,NMAX/16,fs,a,cb) + ib=ibest + cd=cb(ib:ib+144*10-1) + s2=sum(real(cd*conjg(cd)))/(10*144) + cd=cd/sqrt(s2) + do nseq=1,5 + if( nseq.eq.1 ) then ! noncoherent single-symbol detection + sbits1=0.0 + do ibit=1,144 + ib=(ibit-1)*10 + ccor(1,ibit)=sum(cd(ib:ib+9)*conjg(c1(0:9))) + ccor(0,ibit)=sum(cd(ib:ib+9)*conjg(c0(0:9))) + sbits1(ibit)=abs(ccor(1,ibit))-abs(ccor(0,ibit)) + hbits1(ibit)=0 + if(sbits1(ibit).gt.0) hbits1(ibit)=1 + enddo + sbits=sbits1 + hbits=hbits1 + sbits3=sbits1 + hbits3=hbits1 + elseif( nseq.ge.2 ) then + nbit=2*nseq-1 + numseq=2**(nbit) + ps=0 + do ibit=nbit/2+1,144-nbit/2 + ps=0.0 + pmax=0.0 + do iseq=0,numseq-1 + csum=0.0 + cterm=1.0 + k=1 + do i=nbit-1,0,-1 + ibb=iand(iseq/(2**i),1) + csum=csum+ccor(ibb,ibit-(nbit/2+1)+k)*cterm + if(ibb.eq.0) cterm=cterm*cc0 + if(ibb.eq.1) cterm=cterm*cc1 + k=k+1 + enddo + ps(iseq)=abs(csum) + if( ps(iseq) .gt. pmax ) then + pmax=ps(iseq) + ibflag=1 + endif + enddo + if( ibflag .eq. 1 ) then + psbest=ps + ibflag=0 + endif + call getbitmetric(2**(nbit/2),psbest,numseq,sbits3(ibit)) + hbits3(ibit)=0 + if(sbits3(ibit).gt.0) hbits3(ibit)=1 + enddo + sbits=sbits3 + hbits=hbits3 + endif + nsync_qual=count(hbits(1:16).eq.s16) + if(nsync_qual.lt.10) exit + rxdata=sbits(17:144) + rxav=sum(rxdata(1:128))/128.0 + rx2av=sum(rxdata(1:128)*rxdata(1:128))/128.0 + rxsig=sqrt(rx2av-rxav*rxav) + rxdata=rxdata/rxsig + sigma=0.80 + llr(1:128)=2*rxdata/(sigma*sigma) + apmask=0 + max_iterations=40 + do ibias=0,0 + llr2=llr + if(ibias.eq.1) llr2=llr+0.4 + if(ibias.eq.2) llr2=llr-0.4 + call bpdecode128_90(llr2,apmask,max_iterations,message77,cw,nharderror,niterations) + if(nharderror.ge.0) exit + enddo + nhardmin=-1 + if(sum(message77).eq.0) cycle + if( nharderror.ge.0 ) then + write(c77,'(77i1)') message77(1:77) + call unpack77(c77,nrx,message,unpk77_success) + idupe=0 + do i=1,ndecodes + if(decodes(i).eq.message) idupe=1 + enddo + if(idupe.eq.1) exit + ndecodes=ndecodes+1 + decodes(ndecodes)=message + xsnr=db(sybest*sybest) - 115.0 !### Rough estimate of S/N ### + nsnr=nint(xsnr) + freq=f0+dfbest + write(line,1000) hhmmss,nsnr,ibest/750.0,nint(freq),message +1000 format(a6,i4,f5.2,i5,' + ',1x,a37) + open(24,file='all_ft2.txt',status='unknown',position='append') + write(24,1002) cdatetime0,nsnr,ibest/750.0,nint(freq),message, & + nseq,nharderror,nhardmin + if(hhmmss.eq.' ') write(*,1002) cdatetime0,nsnr, & + ibest/750.0,nint(freq),message,nseq,nharderror,nhardmin +1002 format(a17,i4,f6.2,i5,' Rx ',a37,3i5) + close(24) + +!### Temporary: assume most recent decoded message conveys "hiscall". + i0=index(message,' ') + if(i0.ge.3 .and. i0.le.7) then + hiscall=message(i0+1:i0+6) + i1=index(hiscall,' ') + if(i1.gt.0) hiscall=hiscall(1:i1) + endif + nrx=-1 + if(index(message,'CQ ').eq.1) nrx=1 + if((index(message,trim(mycall)//' ').eq.1) .and. & + (index(message,' '//trim(hiscall)//' ').ge.4)) then + if(index(message,' 559 ').gt.8) nrx=2 + if(index(message,' R 559 ').gt.8) nrx=3 + if(index(message,' RR73 ').gt.8) nrx=4 + endif +!### + exit + endif + enddo ! nseq + enddo !candidate list + + return +end subroutine ft2_decode + +subroutine getbitmetric(ib,ps,ns,xmet) + real ps(0:ns-1) + xm1=0 + xm0=0 + do i=0,ns-1 + if( iand(i/ib,1) .eq. 1 .and. ps(i) .gt. xm1 ) xm1=ps(i) + if( iand(i/ib,1) .eq. 0 .and. ps(i) .gt. xm0 ) xm0=ps(i) + enddo + xmet=xm1-xm0 + return +end subroutine getbitmetric + +subroutine downsample2(ci,f0,co) + parameter(NI=144*160,NH=NI/2,NO=NI/16) ! downsample from 200 samples per symbol to 10 + complex ci(0:NI-1),ct(0:NI-1) + complex co(0:NO-1) + fs=12000.0 + df=fs/NI + ct=ci + call four2a(ct,NI,1,-1,1) !c2c FFT to freq domain + i0=nint(f0/df) + ct=cshift(ct,i0) + co=0.0 + co(0)=ct(0) + b=8.0 + do i=1,NO/2 + arg=(i*df/b)**2 + filt=exp(-arg) + co(i)=ct(i)*filt + co(NO-i)=ct(NI-i)*filt + enddo + co=co/NO + call four2a(co,NO,1,1,1) !c2c FFT back to time domain + return +end subroutine downsample2 + +subroutine ft2_downsample(iwave,f0,c) + +! Input: i*2 data in iwave() at sample rate 12000 Hz +! Output: Complex data in c(), sampled at 1200 Hz + + include 'ft2_params.f90' + parameter (NFFT2=NMAX/16) + integer*2 iwave(NMAX) + complex c(0:NMAX/16-1) + complex c1(0:NFFT2-1) + complex cx(0:NMAX/2) + real x(NMAX) + equivalence (x,cx) + + BW=4.0*75 + df=12000.0/NMAX + x=iwave + call four2a(x,NMAX,1,-1,0) !r2c FFT to freq domain + ibw=nint(BW/df) + i0=nint(f0/df) + c1=0. + c1(0)=cx(i0) + do i=1,NFFT2/2 + arg=(i-1)*df/bw + win=exp(-arg*arg) + c1(i)=cx(i0+i)*win + c1(NFFT2-i)=cx(i0-i)*win + enddo + c1=c1/NFFT2 + call four2a(c1,NFFT2,1,1,1) !c2c FFT back to time domain + c=c1(0:NMAX/16-1) + return +end subroutine ft2_downsample diff --git a/lib/ft2/ft2_gfsk_iwave.f90 b/lib/ft2/ft2_gfsk_iwave.f90 new file mode 100644 index 000000000..2611eca09 --- /dev/null +++ b/lib/ft2/ft2_gfsk_iwave.f90 @@ -0,0 +1,88 @@ +subroutine ft2_gfsk_iwave(msg37,f0,snrdb,iwave) + +! Generate waveform for experimental "FT2" mode + + use packjt77 + include 'ft2_params.f90' !Set various constants + parameter (NWAVE=(NN+2)*NSPS) + character msg37*37,msgsent37*37 + real wave(NWAVE),xnoise(NWAVE) + real dphi(NWAVE) + real pulse(480) + + integer itone(NN) + integer*2 iwave(NWAVE) !Generated full-length waveform + logical first + data first/.true./ + save pulse + + twopi=8.0*atan(1.0) + fs=12000.0 !Sample rate (Hz) + dt=1.0/fs !Sample interval (s) + hmod=0.8 !Modulation index (MSK=0.5, FSK=1.0) + tt=NSPS*dt !Duration of symbols (s) + baud=1.0/tt !Keying rate (baud) + bw=1.5*baud !Occupied bandwidth (Hz) + txt=NZ*dt !Transmission length (s) + bandwidth_ratio=2500.0/(fs/2.0) +! sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb) +! if(snrdb.gt.90.0) sig=1.0 + txt=NN*NSPS/12000.0 + + if(first) then +! The filtered frequency pulse + do i=1,480 + tt=(i-240.5)/160.0 + pulse(i)=gfsk_pulse(1.0,tt) + enddo + dphi_peak=twopi*(hmod/2.0)/real(NSPS) + first=.false. + endif + +! Source-encode, then get itone(): + itype=1 + call genft2(msg37,0,msgsent37,itone,itype) + +! Create the instantaneous frequency waveform + dphi=0.0 + do j=1,NN + ib=(j-1)*160+1 + ie=ib+480-1 + dphi(ib:ie)=dphi(ib:ie)+dphi_peak*pulse*(2*itone(j)-1) + enddo + + phi=0.0 + wave=0.0 + sqrt2=sqrt(2.) + dphi=dphi+twopi*f0*dt + do j=1,NWAVE + wave(j)=sqrt2*sin(phi) + sqsig=sqsig + wave(j)**2 + phi=mod(phi+dphi(j),twopi) + enddo + wave(1:160)=wave(1:160)*(1.0-cos(twopi*(/(i,i=0,159)/)/320.0) )/2.0 + wave(145*160+1:146*160)=wave(145*160+1:146*160)*(1.0+cos(twopi*(/(i,i=0,159)/)/320.0 ))/2.0 + wave(146*160+1:)=0. + + if(snrdb.gt.90.0) then + iwave=nint((32767.0/sqrt(2.0))*wave) + return + endif + + sqnoise=1.e-30 + if(snrdb.lt.90) then + do i=1,NWAVE !Add gaussian noise at specified SNR + xnoise(i)=gran() !Noise has rms = 1.0 + enddo + endif + xnoise=xnoise*sqrt(0.5*fs/2500.0) + fac=30.0 + snr_amplitude=10.0**(0.05*snrdb) + wave=fac*(snr_amplitude*wave + xnoise) + datpk=maxval(abs(wave)) + print*,'A',snr_amplitude,datpk + + iwave=nint((30000.0/datpk)*wave) + + return +end subroutine ft2_gfsk_iwave diff --git a/lib/ft2/ft2_iwave.f90 b/lib/ft2/ft2_iwave.f90 new file mode 100644 index 000000000..10b9908de --- /dev/null +++ b/lib/ft2/ft2_iwave.f90 @@ -0,0 +1,64 @@ +subroutine ft2_iwave(msg37,f0,snrdb,iwave) + +! Generate waveform for experimental "FT2" mode + + use packjt77 + include 'ft2_params.f90' !Set various constants + parameter (NWAVE=NN*NSPS) + character msg37*37,msgsent37*37 + real wave(NWAVE),xnoise(NWAVE) + integer itone(NN) + integer*2 iwave(NWAVE) !Generated full-length waveform + + twopi=8.0*atan(1.0) + fs=12000.0 !Sample rate (Hz) + dt=1.0/fs !Sample interval (s) + hmod=0.8 !Modulation index (MSK=0.5, FSK=1.0) + tt=NSPS*dt !Duration of symbols (s) + baud=1.0/tt !Keying rate (baud) + bw=1.5*baud !Occupied bandwidth (Hz) + txt=NZ*dt !Transmission length (s) + bandwidth_ratio=2500.0/(fs/2.0) +! sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb) +! if(snrdb.gt.90.0) sig=1.0 + txt=NN*NSPS/12000.0 + +! Source-encode, then get itone(): + itype=1 + call genft2(msg37,0,msgsent37,itone,itype) + + k=0 + phi=0.0 + sqsig=0. + do j=1,NN !Generate real waveform + dphi=twopi*(f0*dt+(hmod/2.0)*(2*itone(j)-1)/real(NSPS)) + do i=1,NSPS + k=k+1 + wave(k)=sqrt(2.0)*sin(phi) !Signal has rms = 1.0 + sqsig=sqsig + wave(k)**2 + phi=mod(phi+dphi,twopi) + enddo + enddo + + if(snrdb.gt.90.0) then + iwave=nint((32767.0/sqrt(2.0))*wave) + return + endif + + sqnoise=1.e-30 + if(snrdb.lt.90) then + do i=1,NWAVE !Add gaussian noise at specified SNR + xnoise(i)=gran() !Noise has rms = 1.0 + enddo + endif + xnoise=xnoise*sqrt(0.5*fs/2500.0) + fac=30.0 + snr_amplitude=10.0**(0.05*snrdb) + wave=fac*(snr_amplitude*wave + xnoise) + datpk=maxval(abs(wave)) + print*,'A',snr_amplitude,datpk + + iwave=nint((30000.0/datpk)*wave) + + return +end subroutine ft2_iwave diff --git a/lib/ft2/ft2_params.f90 b/lib/ft2/ft2_params.f90 new file mode 100644 index 000000000..4751e47e4 --- /dev/null +++ b/lib/ft2/ft2_params.f90 @@ -0,0 +1,12 @@ +! LDPC (128,90) code +parameter (KK=90) !Information bits (77 + CRC13) +parameter (ND=128) !Data symbols +parameter (NS=16) !Sync symbols (2x8) +parameter (NN=NS+ND) !Total channel symbols (144) +parameter (NSPS=160) !Samples per symbol at 12000 S/s +parameter (NZ=NSPS*NN) !Samples in full 1.92 s waveform (23040) +parameter (NMAX=30000) !Samples in iwave (2.5*12000) +parameter (NFFT1=400, NH1=NFFT1/2) !Length of FFTs for symbol spectra +parameter (NSTEP=NSPS/4) !Rough time-sync step size +parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps) +parameter (NDOWN=16) !Downsample factor diff --git a/lib/ft2/ft2audio.c b/lib/ft2/ft2audio.c new file mode 100644 index 000000000..b5f19fa40 --- /dev/null +++ b/lib/ft2/ft2audio.c @@ -0,0 +1,347 @@ +#include +#include "portaudio.h" +#include +#include + +int iaa; +int icc; +double total_time=0.0; + +// Definition of structure pointing to the audio data +typedef struct +{ + int *iwrite; + int *itx; + int *TxOK; + int *Transmitting; + int *nwave; + int *nright; + int nring; + int nfs; + short *y1; + short *y2; + short *iwave; +} paTestData; + +// Input callback routine: +static int +SoundIn( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *in = (short*)inputBuffer; + unsigned int i; + static int ia=0; + + if(*data->Transmitting) return 0; + + if(statusFlags!=0) printf("Status flags %d\n",(int)statusFlags); + + if((statusFlags&1) == 0) { + //increment buffer pointers only if data available + ia=*data->iwrite; + if(*data->nright==0) { //Use left channel for input + for(i=0; iy1[ia] = (*in++); + data->y2[ia] = (*in++); + ia++; + } + } else { //Use right channel + for(i=0; iy2[ia] = (*in++); + data->y1[ia] = (*in++); + ia++; + } + } + } + + if(ia >= data->nring) ia=0; //Wrap buffer pointer if necessary + *data->iwrite = ia; //Save buffer pointer + iaa=ia; + total_time += (double)framesPerBuffer/12000.0; + // printf("iwrite: %d\n",*data->iwrite); + return 0; +} + +// Output callback routine: +static int +SoundOut( void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ) +{ + paTestData *data = (paTestData*)userData; + short *wptr = (short*)outputBuffer; + unsigned int i,n; + static short int n2; + static int ic=0; + static int TxOKz=0; + static clock_t tstart=-1; + static clock_t tend=-1; + static int nsent=0; + + // printf("txOK: %d %d\n",TxOKz,*data->TxOK); + + if(*data->TxOK && (!TxOKz)) ic=0; //Reset buffer pointer to start Tx + *data->Transmitting=*data->TxOK; //Set the "transmitting" flag + + if(*data->TxOK) { + if(!TxOKz) { + // Start of a transmission + tstart=clock(); + nsent=0; + // printf("Start Tx\n"); + } + TxOKz=*data->TxOK; + for(i=0 ; i < framesPerBuffer; i++ ) { + n2=data->iwave[ic]; + *wptr++ = n2; //left + *wptr++ = n2; //right + ic++; + + if(ic > *data->nwave) { + *data->TxOK = 0; + *data->Transmitting = 0; + *data->iwrite = 0; //Reset Rx buffer pointer to 0 + ic=0; + tend=clock(); + double TxT=((double)(tend-tstart))/CLOCKS_PER_SEC; + // printf("End Tx, TxT = %f nSent = %d\n",TxT,nsent); + break; + } + } + nsent += framesPerBuffer; + } else { + memset((void*)outputBuffer, 0, 2*sizeof(short)*framesPerBuffer); + } + *data->itx = icc; //Save buffer pointer + icc=ic; + return 0; +} + +/*******************************************************************/ +int ft2audio_(int *ndevin, int *ndevout, int *npabuf, int *nright, + short y1[], short y2[], int *nring, int *iwrite, + int *itx, short iwave[], int *nwave, int *nfsample, + int *TxOK, int *Transmitting, int *ngo) + +{ + paTestData data; + PaStream *instream, *outstream; + PaStreamParameters inputParameters, outputParameters; + // PaStreamInfo *streamInfo; + + int nfpb = *npabuf; + int nSampleRate = *nfsample; + int ndevice_in = *ndevin; + int ndevice_out = *ndevout; + double dSampleRate = (double) *nfsample; + PaError err_init, err_open_in, err_open_out, err_start_in, err_start_out; + PaError err = 0; + + data.iwrite = iwrite; + data.itx = itx; + data.TxOK = TxOK; + data.Transmitting = Transmitting; + data.y1 = y1; + data.y2 = y2; + data.nring = *nring; + data.nright = nright; + data.nwave = nwave; + data.iwave = iwave; + data.nfs = nSampleRate; + + err_init = Pa_Initialize(); // Initialize PortAudio + + if(err_init) { + printf("Error initializing PortAudio.\n"); + printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_init), + err_init); + Pa_Terminate(); // I don't think we need this but... + return(-1); + } + + // printf("Opening device %d for input, %d for output...\n", + // ndevice_in,ndevice_out); + + inputParameters.device = ndevice_in; + inputParameters.channelCount = 2; + inputParameters.sampleFormat = paInt16; + inputParameters.suggestedLatency = 0.2; + inputParameters.hostApiSpecificStreamInfo = NULL; + +// Test if this configuration actually works, so we do not run into an +// ugly assertion + err_open_in = Pa_IsFormatSupported(&inputParameters, NULL, dSampleRate); + + if (err_open_in == 0) { + err_open_in = Pa_OpenStream( + &instream, //address of stream + &inputParameters, + NULL, + dSampleRate, //Sample rate + nfpb, //Frames per buffer + paNoFlag, + (PaStreamCallback *)SoundIn, //Callback routine + (void *)&data); //address of data structure + + if(err_open_in) { // We should have no error here usually + printf("Error opening input audio stream:\n"); + printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_in), + err_open_in); + err = 1; + } else { + // printf("Successfully opened audio input.\n"); + } + } else { + printf("Error opening input audio stream.\n"); + printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_in), + err_open_in); + err = 1; + } + + outputParameters.device = ndevice_out; + outputParameters.channelCount = 2; + outputParameters.sampleFormat = paInt16; + outputParameters.suggestedLatency = 0.2; + outputParameters.hostApiSpecificStreamInfo = NULL; + +// Test if this configuration actually works, so we do not run into an +// ugly assertion. + err_open_out = Pa_IsFormatSupported(NULL, &outputParameters, dSampleRate); + + if (err_open_out == 0) { + err_open_out = Pa_OpenStream( + &outstream, //address of stream + NULL, + &outputParameters, + dSampleRate, //Sample rate + nfpb, //Frames per buffer + paNoFlag, + (PaStreamCallback *)SoundOut, //Callback routine + (void *)&data); //address of data structure + + if(err_open_out) { // We should have no error here usually + printf("Error opening output audio stream!\n"); + printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_out), + err_open_out); + err += 2; + } else { + // printf("Successfully opened audio output.\n"); + } + } else { + printf("Error opening output audio stream.\n"); + printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_open_out), + err_open_out); + err += 2; + } + + // if there was no error in opening both streams start them + if (err == 0) { + err_start_in = Pa_StartStream(instream); //Start input stream + if(err_start_in) { + printf("Error starting input audio stream!\n"); + printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_start_in), + err_start_in); + err += 4; + } + + err_start_out = Pa_StartStream(outstream); //Start output stream + if(err_start_out) { + printf("Error starting output audio stream!\n"); + printf("\tErrortext: %s\n\tNumber: %d\n",Pa_GetErrorText(err_start_out), + err_start_out); + err += 8; + } + } + + if (err == 0) printf("Audio streams running normally.\n******************************************************************\n"); + + while( Pa_IsStreamActive(instream) && (*ngo != 0) && (err == 0) ) { + int ic1=0; + int ic2=0; + if(_kbhit()) ic1 = _getch(); + if(_kbhit()) ic2 = _getch(); + // if(ic1!=0 || ic2!=0) printf("%d %d %d\n",iaa,ic1,ic2); + update_(&total_time,&ic1,&ic2); + Pa_Sleep(100); + } + + Pa_AbortStream(instream); // Abort stream + Pa_CloseStream(instream); // Close stream, we're done. + Pa_AbortStream(outstream); // Abort stream + Pa_CloseStream(outstream); // Close stream, we're done. + + Pa_Terminate(); + + return(err); +} + + +int padevsub_(int *idevin, int *idevout) +{ + int numdev,ndefin,ndefout; + int nchin[101], nchout[101]; + int i, devIdx; + int numDevices; + const PaDeviceInfo *pdi; + PaError err; + + Pa_Initialize(); + numDevices = Pa_GetDeviceCount(); + numdev = numDevices; + + if( numDevices < 0 ) { + err = numDevices; + Pa_Terminate(); + return err; + } + + if ((devIdx = Pa_GetDefaultInputDevice()) > 0) { + ndefin = devIdx; + } else { + ndefin = 0; + } + + if ((devIdx = Pa_GetDefaultOutputDevice()) > 0) { + ndefout = devIdx; + } else { + ndefout = 0; + } + + printf("\nAudio Input Output Device Name\n"); + printf("Device Channels Channels\n"); + printf("------------------------------------------------------------------\n"); + + for( i=0; i < numDevices; i++ ) { + pdi = Pa_GetDeviceInfo(i); +// if(i == Pa_GetDefaultInputDevice()) ndefin = i; +// if(i == Pa_GetDefaultOutputDevice()) ndefout = i; + nchin[i]=pdi->maxInputChannels; + nchout[i]=pdi->maxOutputChannels; + printf(" %2d %2d %2d %s\n",i,nchin[i],nchout[i], + pdi->name); + } + + printf("\nUser requested devices: Input = %2d Output = %2d\n", + *idevin,*idevout); + printf("Default devices: Input = %2d Output = %2d\n", + ndefin,ndefout); + if((*idevin<0) || (*idevin>=numdev)) *idevin=ndefin; + if((*idevout<0) || (*idevout>=numdev)) *idevout=ndefout; + if((*idevin==0) && (*idevout==0)) { + *idevin=ndefin; + *idevout=ndefout; + } + printf("Will open devices: Input = %2d Output = %2d\n", + *idevin,*idevout); + + Pa_Terminate(); + + return 0; +} + diff --git a/lib/ft2/g4.cmd b/lib/ft2/g4.cmd new file mode 100644 index 000000000..0894dbebe --- /dev/null +++ b/lib/ft2/g4.cmd @@ -0,0 +1,7 @@ +gcc -c ft2audio.c +gcc -c ptt.c +gfortran -c ../77bit/packjt77.f90 +gfortran -c ../wavhdr.f90 +gfortran -c ../crc.f90 +gfortran -o ft2 -fbounds-check -fno-second-underscore -ffpe-trap=invalid,zero -Wall -Wno-conversion -Wno-character-truncation ft2.f90 ft2_iwave.f90 ft2_decode.f90 getcandidates2.f90 ft2audio.o ptt.o /JTSDK/wsjtx-output/qt55/2.1.0/Release/build/libwsjt_fort.a /JTSDK/wsjtx-output/qt55/2.1.0/Release/build/libwsjt_cxx.a libportaudio.a ../libfftw3f_win.a -lwinmm +rm *.o *.mod diff --git a/lib/ft2/gcom1.f90 b/lib/ft2/gcom1.f90 new file mode 100644 index 000000000..9402f9d9e --- /dev/null +++ b/lib/ft2/gcom1.f90 @@ -0,0 +1,34 @@ +! Variable Purpose +!--------------------------------------------------------------------------- +integer NRING !Length of Rx ring buffer +integer NTZ !Length of Tx waveform in samples +parameter(NRING=230400) !Ring buffer at 12000 samples/sec +parameter(NTZ=23040) !144*160 +parameter(NMAX=30000) !2.5*12000 +real snrdb +integer ndevin !Device# for audio input +integer ndevout !Device# for audio output +integer iwrite !Pointer to Rx ring buffer +integer itx !Pointer to Tx buffer +integer ngo !Set to 0 to terminate audio streams +integer nTransmitting !Actually transmitting? +integer nTxOK !OK to transmit? +integer nport !COM port for PTT +logical tx_once !Transmit one message, then exit +logical ltx !True if msg i has been transmitted +logical lrx !True if msg i has been received +logical autoseq +logical QSO_in_progress +integer*2 y1 !Ring buffer for audio channel 0 +integer*2 y2 !Ring buffer for audio channel 1 +integer*2 iwave !Data for Tx audio +character*6 mycall +character*6 hiscall +character*6 hiscall_next +character*4 mygrid +character*3 exch +character*37 txmsg + +common/gcom1/snrdb,ndevin,ndevout,iwrite,itx,ngo,nTransmitting,nTxOK,nport, & + ntxed,tx_once,y1(NRING),y2(NRING),iwave(NTZ+3*1152),ltx(5),lrx(5), & + autoseq,QSO_in_progress,mycall,hiscall,hiscall_next,mygrid,exch,txmsg diff --git a/lib/ft2/genft2.f90 b/lib/ft2/genft2.f90 new file mode 100644 index 000000000..2eb36bccc --- /dev/null +++ b/lib/ft2/genft2.f90 @@ -0,0 +1,86 @@ +subroutine genft2(msg0,ichk,msgsent,i4tone,itype) +! s8 + 48bits + s8 + 80 bits = 144 bits (72ms message duration) +! +! Encode an MSK144 message +! Input: +! - msg0 requested message to be transmitted +! - ichk if ichk=1, return only msgsent +! if ichk.ge.10000, set imsg=ichk-10000 for short msg +! - msgsent message as it will be decoded +! - i4tone array of audio tone values, 0 or 1 +! - itype message type +! 1 = 77 bit message +! 7 = 16 bit message " Rpt" + + use iso_c_binding, only: c_loc,c_size_t + use packjt77 + character*37 msg0 + character*37 message !Message to be generated + character*37 msgsent !Message as it will be received + character*77 c77 + integer*4 i4tone(144) + integer*1 codeword(128) + integer*1 msgbits(77) + integer*1 bitseq(144) !Tone #s, data and sync (values 0-1) + integer*1 s16(16) + real*8 xi(864),xq(864),pi,twopi + data s16/0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0/ + equivalence (ihash,i1hash) + logical unpk77_success + + nsym=128 + pi=4.0*atan(1.0) + twopi=8.*atan(1.0) + + message(1:37)=' ' + itype=1 + if(msg0(1:1).eq.'@') then !Generate a fixed tone + read(msg0(2:5),*,end=1,err=1) nfreq !at specified frequency + go to 2 +1 nfreq=1000 +2 i4tone(1)=nfreq + else + message=msg0 + + do i=1, 37 + if(ichar(message(i:i)).eq.0) then + message(i:37)=' ' + exit + endif + enddo + do i=1,37 !Strip leading blanks + if(message(1:1).ne.' ') exit + message=message(i+1:) + enddo + + if(message(1:1).eq.'<') then + i2=index(message,'>') + i1=0 + if(i2.gt.0) i1=index(message(1:i2),' ') + if(i1.gt.0) then + call genmsk40(message,msgsent,ichk,i4tone,itype) + if(itype.lt.0) go to 999 + i4tone(41)=-40 + go to 999 + endif + endif + + i3=-1 + n3=-1 + call pack77(message,i3,n3,c77) + call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent + + if(ichk.eq.1) go to 999 + read(c77,"(77i1)") msgbits + call encode_128_90(msgbits,codeword) + +!Create 144-bit channel vector: + bitseq=0 + bitseq(1:16)=s16 + bitseq(17:144)=codeword + + i4tone=bitseq + endif + +999 return +end subroutine genft2 diff --git a/lib/ft2/getcandidates2a.f90 b/lib/ft2/getcandidates2a.f90 new file mode 100644 index 000000000..8e7209c9c --- /dev/null +++ b/lib/ft2/getcandidates2a.f90 @@ -0,0 +1,64 @@ +subroutine getcandidates2a(id,fa,fb,maxcand,savg,candidate,ncand) + +! For now, hardwired to find the largest peak in the average spectrum + + include 'ft2_params.f90' + real s(NH1,NHSYM) + real savg(NH1),savsm(NH1) + real x(NFFT1) + complex cx(0:NH1) + real candidate(3,100) + integer*2 id(NMAX) + integer*1 s8(8) + integer indx(NH1) + data s8/0,1,1,1,0,0,1,0/ + equivalence (x,cx) + +! Compute symbol spectra, stepping by NSTEP steps. + savg=0. + tstep=NSTEP/12000.0 + df=12000.0/NFFT1 !3.125 Hz + fac=1.0/300.0 + do j=1,NHSYM + ia=(j-1)*NSTEP + 1 + ib=ia+NSPS-1 + x(1:NSPS)=fac*id(ia:ib) + x(NSPS+1:)=0. + call four2a(x,NFFT1,1,-1,0) !r2c FFT + do i=1,NH1 + s(i,j)=real(cx(i))**2 + aimag(cx(i))**2 + enddo + savg=savg + s(1:NH1,j) !Average spectrum + enddo + savsm=0. + do i=2,NH1-1 + savsm(i)=sum(savg(i-1:i+1))/3. + enddo + savsm(1)=savg(1) + savsm(NH1)=savg(NH1) + + nfa=nint(fa/df) + nfb=nint(fb/df) + np=nfb-nfa+1 + indx=0 + call indexx(savsm(nfa:nfb),np,indx) + xn=savsm(nfa+indx(nint(0.3*np))) + if(xn.ne.0) savsm=savsm/xn + imax=-1 + xmax=-99. + do i=2,NH1-1 + if(savsm(i).gt.savsm(i-1).and. & + savsm(i).gt.savsm(i+1).and. & + savsm(i).gt.xmax) then + xmax=savsm(i) + imax=i + endif + enddo + f0=imax*df + if(xmax.gt.1.2) then + if(ncand.lt.maxcand) ncand=ncand+1 + candidate(1,ncand)=f0 + endif + + return +end subroutine getcandidates2a diff --git a/lib/ft2/gfsk_pulse.f90 b/lib/ft2/gfsk_pulse.f90 new file mode 100644 index 000000000..99ab78e35 --- /dev/null +++ b/lib/ft2/gfsk_pulse.f90 @@ -0,0 +1,6 @@ +real function gfsk_pulse(b,t) + pi=4.*atan(1.0) + c=pi*sqrt(2.0/log(2.0)) + gfsk_pulse=0.5*(erf(c*b*(t+0.5))-erf(c*b*(t-0.5))) + return +end function gfsk_pulse diff --git a/lib/ft2/libportaudio.a b/lib/ft2/libportaudio.a new file mode 100644 index 000000000..f20f02c16 Binary files /dev/null and b/lib/ft2/libportaudio.a differ diff --git a/lib/ft2/libwsjt_cxx.a b/lib/ft2/libwsjt_cxx.a new file mode 100644 index 000000000..d10d509cf Binary files /dev/null and b/lib/ft2/libwsjt_cxx.a differ diff --git a/lib/ft2/libwsjt_fort.a b/lib/ft2/libwsjt_fort.a new file mode 100644 index 000000000..7884c85bb Binary files /dev/null and b/lib/ft2/libwsjt_fort.a differ diff --git a/lib/ft2/portaudio.h b/lib/ft2/portaudio.h new file mode 100644 index 000000000..250fba021 --- /dev/null +++ b/lib/ft2/portaudio.h @@ -0,0 +1,1123 @@ + +#ifndef PORTAUDIO_H +#define PORTAUDIO_H +/* + * $Id: portaudio.h,v 1.1 2005/11/29 21:27:24 joe Exp $ + * PortAudio Portable Real-Time Audio Library + * PortAudio API Header File + * Latest version available at: http://www.portaudio.com/ + * + * Copyright (c) 1999-2002 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/** @file + @brief The PortAudio API. +*/ + + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + + +/** Retrieve the release number of the currently running PortAudio build, + eg 1900. +*/ +int Pa_GetVersion( void ); + + +/** Retrieve a textual description of the current PortAudio build, + eg "PortAudio V19-devel 13 October 2002". +*/ +const char* Pa_GetVersionText( void ); + + +/** Error codes returned by PortAudio functions. + Note that with the exception of paNoError, all PaErrorCodes are negative. +*/ + +typedef int PaError; +typedef enum PaErrorCode +{ + paNoError = 0, + + paNotInitialized = -10000, + paUnanticipatedHostError, + paInvalidChannelCount, + paInvalidSampleRate, + paInvalidDevice, + paInvalidFlag, + paSampleFormatNotSupported, + paBadIODeviceCombination, + paInsufficientMemory, + paBufferTooBig, + paBufferTooSmall, + paNullCallback, + paBadStreamPtr, + paTimedOut, + paInternalError, + paDeviceUnavailable, + paIncompatibleHostApiSpecificStreamInfo, + paStreamIsStopped, + paStreamIsNotStopped, + paInputOverflowed, + paOutputUnderflowed, + paHostApiNotFound, + paInvalidHostApi, + paCanNotReadFromACallbackStream, /**< @todo review error code name */ + paCanNotWriteToACallbackStream, /**< @todo review error code name */ + paCanNotReadFromAnOutputOnlyStream, /**< @todo review error code name */ + paCanNotWriteToAnInputOnlyStream, /**< @todo review error code name */ + paIncompatibleStreamHostApi +} PaErrorCode; + + +/** Translate the supplied PortAudio error code into a human readable + message. +*/ +const char *Pa_GetErrorText( PaError errorCode ); + + +/** Library initialization function - call this before using PortAudio. + This function initialises internal data structures and prepares underlying + host APIs for use. This function MUST be called before using any other + PortAudio API functions. + + If Pa_Initialize() is called multiple times, each successful + call must be matched with a corresponding call to Pa_Terminate(). + Pairs of calls to Pa_Initialize()/Pa_Terminate() may overlap, and are not + required to be fully nested. + + Note that if Pa_Initialize() returns an error code, Pa_Terminate() should + NOT be called. + + @return paNoError if successful, otherwise an error code indicating the cause + of failure. + + @see Pa_Terminate +*/ +PaError Pa_Initialize( void ); + + +/** Library termination function - call this when finished using PortAudio. + This function deallocates all resources allocated by PortAudio since it was + initializied by a call to Pa_Initialize(). In cases where Pa_Initialise() has + been called multiple times, each call must be matched with a corresponding call + to Pa_Terminate(). The final matching call to Pa_Terminate() will automatically + close any PortAudio streams that are still open. + + Pa_Terminate() MUST be called before exiting a program which uses PortAudio. + Failure to do so may result in serious resource leaks, such as audio devices + not being available until the next reboot. + + @return paNoError if successful, otherwise an error code indicating the cause + of failure. + + @see Pa_Initialize +*/ +PaError Pa_Terminate( void ); + + + +/** The type used to refer to audio devices. Values of this type usually + range from 0 to (Pa_DeviceCount-1), and may also take on the PaNoDevice + and paUseHostApiSpecificDeviceSpecification values. + + @see Pa_DeviceCount, paNoDevice, paUseHostApiSpecificDeviceSpecification +*/ +typedef int PaDeviceIndex; + + +/** A special PaDeviceIndex value indicating that no device is available, + or should be used. + + @see PaDeviceIndex +*/ +#define paNoDevice ((PaDeviceIndex)-1) + + +/** A special PaDeviceIndex value indicating that the device(s) to be used + are specified in the host api specific stream info structure. + + @see PaDeviceIndex +*/ +#define paUseHostApiSpecificDeviceSpecification ((PaDeviceIndex)-2) + + +/* Host API enumeration mechanism */ + +/** The type used to enumerate to host APIs at runtime. Values of this type + range from 0 to (Pa_GetHostApiCount()-1). + + @see Pa_GetHostApiCount +*/ +typedef int PaHostApiIndex; + + +/** Retrieve the number of available host APIs. Even if a host API is + available it may have no devices available. + + @return A non-negative value indicating the number of available host APIs + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + @see PaHostApiIndex +*/ +PaHostApiIndex Pa_GetHostApiCount( void ); + + +/** Retrieve the index of the default host API. The default host API will be + the lowest common denominator host API on the current platform and is + unlikely to provide the best performance. + + @return A non-negative value ranging from 0 to (Pa_GetHostApiCount()-1) + indicating the default host API index or, a PaErrorCode (which are always + negative) if PortAudio is not initialized or an error is encountered. +*/ +PaHostApiIndex Pa_GetDefaultHostApi( void ); + + +/** Unchanging unique identifiers for each supported host API. This type + is used in the PaHostApiInfo structure. The values are guaranteed to be + unique and to never change, thus allowing code to be written that + conditionally uses host API specific extensions. + + New type ids will be allocated when support for a host API reaches + "public alpha" status, prior to that developers should use the + paInDevelopment type id. + + @see PaHostApiInfo +*/ +typedef enum PaHostApiTypeId +{ + paInDevelopment=0, /* use while developing support for a new host API */ + paDirectSound=1, + paMME=2, + paASIO=3, + paSoundManager=4, + paCoreAudio=5, + paOSS=7, + paALSA=8, + paAL=9, + paBeOS=10, + paWDMKS=11, + paJACK=12 +} PaHostApiTypeId; + + +/** A structure containing information about a particular host API. */ + +typedef struct PaHostApiInfo +{ + /** this is struct version 1 */ + int structVersion; + /** The well known unique identifier of this host API @see PaHostApiTypeId */ + PaHostApiTypeId type; + /** A textual description of the host API for display on user interfaces. */ + const char *name; + + /** The number of devices belonging to this host API. This field may be + used in conjunction with Pa_HostApiDeviceIndexToDeviceIndex() to enumerate + all devices for this host API. + @see Pa_HostApiDeviceIndexToDeviceIndex + */ + int deviceCount; + + /** The the default input device for this host API. The value will be a + device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice + if no default input device is available. + */ + PaDeviceIndex defaultInputDevice; + + /** The the default output device for this host API. The value will be a + device index ranging from 0 to (Pa_GetDeviceCount()-1), or paNoDevice + if no default output device is available. + */ + PaDeviceIndex defaultOutputDevice; + +} PaHostApiInfo; + + +/** Retrieve a pointer to a structure containing information about a specific + host Api. + + @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) + + @return A pointer to an immutable PaHostApiInfo structure describing + a specific host API. If the hostApi parameter is out of range or an error + is encountered, the function returns NULL. + + The returned structure is owned by the PortAudio implementation and must not + be manipulated or freed. The pointer is only guaranteed to be valid between + calls to Pa_Initialize() and Pa_Terminate(). +*/ +const PaHostApiInfo * Pa_GetHostApiInfo( PaHostApiIndex hostApi ); + + +/** Convert a static host API unique identifier, into a runtime + host API index. + + @param type A unique host API identifier belonging to the PaHostApiTypeId + enumeration. + + @return A valid PaHostApiIndex ranging from 0 to (Pa_GetHostApiCount()-1) or, + a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + The paHostApiNotFound error code indicates that the host API specified by the + type parameter is not available. + + @see PaHostApiTypeId +*/ +PaHostApiIndex Pa_HostApiTypeIdToHostApiIndex( PaHostApiTypeId type ); + + +/** Convert a host-API-specific device index to standard PortAudio device index. + This function may be used in conjunction with the deviceCount field of + PaHostApiInfo to enumerate all devices for the specified host API. + + @param hostApi A valid host API index ranging from 0 to (Pa_GetHostApiCount()-1) + + @param hostApiDeviceIndex A valid per-host device index in the range + 0 to (Pa_GetHostApiInfo(hostApi)->deviceCount-1) + + @return A non-negative PaDeviceIndex ranging from 0 to (Pa_GetDeviceCount()-1) + or, a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. + + A paInvalidHostApi error code indicates that the host API index specified by + the hostApi parameter is out of range. + + A paInvalidDevice error code indicates that the hostApiDeviceIndex parameter + is out of range. + + @see PaHostApiInfo +*/ +PaDeviceIndex Pa_HostApiDeviceIndexToDeviceIndex( PaHostApiIndex hostApi, + int hostApiDeviceIndex ); + + + +/** Structure used to return information about a host error condition. +*/ +typedef struct PaHostErrorInfo{ + PaHostApiTypeId hostApiType; /**< the host API which returned the error code */ + long errorCode; /**< the error code returned */ + const char *errorText; /**< a textual description of the error if available, otherwise a zero-length string */ +}PaHostErrorInfo; + + +/** Return information about the last host error encountered. The error + information returned by Pa_GetLastHostErrorInfo() will never be modified + asyncronously by errors occurring in other PortAudio owned threads + (such as the thread that manages the stream callback.) + + This function is provided as a last resort, primarily to enhance debugging + by providing clients with access to all available error information. + + @return A pointer to an immutable structure constaining information about + the host error. The values in this structure will only be valid if a + PortAudio function has previously returned the paUnanticipatedHostError + error code. +*/ +const PaHostErrorInfo* Pa_GetLastHostErrorInfo( void ); + + + +/* Device enumeration and capabilities */ + +/** Retrieve the number of available devices. The number of available devices + may be zero. + + @return A non-negative value indicating the number of available devices or, + a PaErrorCode (which are always negative) if PortAudio is not initialized + or an error is encountered. +*/ +PaDeviceIndex Pa_GetDeviceCount( void ); + + +/** Retrieve the index of the default input device. The result can be + used in the inputDevice parameter to Pa_OpenStream(). + + @return The default input device index for the default host API, or paNoDevice + if no default input device is available or an error was encountered. +*/ +PaDeviceIndex Pa_GetDefaultInputDevice( void ); + + +/** Retrieve the index of the default output device. The result can be + used in the outputDevice parameter to Pa_OpenStream(). + + @return The default output device index for the defualt host API, or paNoDevice + if no default output device is available or an error was encountered. + + @note + On the PC, the user can specify a default device by + setting an environment variable. For example, to use device #1. +
+ set PA_RECOMMENDED_OUTPUT_DEVICE=1
+
+ The user should first determine the available device ids by using + the supplied application "pa_devs". +*/ +PaDeviceIndex Pa_GetDefaultOutputDevice( void ); + + +/** The type used to represent monotonic time in seconds that can be used + for syncronisation. The type is used for the outTime argument to the + PaStreamCallback and as the result of Pa_GetStreamTime(). + + @see PaStreamCallback, Pa_GetStreamTime +*/ +typedef double PaTime; + + +/** A type used to specify one or more sample formats. Each value indicates + a possible format for sound data passed to and from the stream callback, + Pa_ReadStream and Pa_WriteStream. + + The standard formats paFloat32, paInt16, paInt32, paInt24, paInt8 + and aUInt8 are usually implemented by all implementations. + + The floating point representation (paFloat32) uses +1.0 and -1.0 as the + maximum and minimum respectively. + + paUInt8 is an unsigned 8 bit format where 128 is considered "ground" + + The paNonInterleaved flag indicates that a multichannel buffer is passed + as a set of non-interleaved pointers. + + @see Pa_OpenStream, Pa_OpenDefaultStream, PaDeviceInfo + @see paFloat32, paInt16, paInt32, paInt24, paInt8 + @see paUInt8, paCustomFormat, paNonInterleaved +*/ +typedef unsigned long PaSampleFormat; + + +#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */ +#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */ +#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */ +#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */ +#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */ +#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */ +#define paCustomFormat ((PaSampleFormat) 0x00010000)/**< @see PaSampleFormat */ + +#define paNonInterleaved ((PaSampleFormat) 0x80000000) + +/** A structure providing information and capabilities of PortAudio devices. + Devices may support input, output or both input and output. +*/ +typedef struct PaDeviceInfo +{ + int structVersion; /* this is struct version 2 */ + const char *name; + PaHostApiIndex hostApi; /* note this is a host API index, not a type id*/ + + int maxInputChannels; + int maxOutputChannels; + + /* Default latency values for interactive performance. */ + PaTime defaultLowInputLatency; + PaTime defaultLowOutputLatency; + /* Default latency values for robust non-interactive applications (eg. playing sound files). */ + PaTime defaultHighInputLatency; + PaTime defaultHighOutputLatency; + + double defaultSampleRate; +} PaDeviceInfo; + + +/** Retrieve a pointer to a PaDeviceInfo structure containing information + about the specified device. + @return A pointer to an immutable PaDeviceInfo structure. If the device + parameter is out of range the function returns NULL. + + @param device A valid device index in the range 0 to (Pa_GetDeviceCount()-1) + + @note PortAudio manages the memory referenced by the returned pointer, + the client must not manipulate or free the memory. The pointer is only + guaranteed to be valid between calls to Pa_Initialize() and Pa_Terminate(). + + @see PaDeviceInfo, PaDeviceIndex +*/ +const PaDeviceInfo* Pa_GetDeviceInfo( PaDeviceIndex device ); + + +/** Parameters for one direction (input or output) of a stream. +*/ +typedef struct PaStreamParameters +{ + /** A valid device index in the range 0 to (Pa_GetDeviceCount()-1) + specifying the device to be used or the special constant + paUseHostApiSpecificDeviceSpecification which indicates that the actual + device(s) to use are specified in hostApiSpecificStreamInfo. + This field must not be set to paNoDevice. + */ + PaDeviceIndex device; + + /** The number of channels of sound to be delivered to the + stream callback or accessed by Pa_ReadStream() or Pa_WriteStream(). + It can range from 1 to the value of maxInputChannels in the + PaDeviceInfo record for the device specified by the device parameter. + */ + int channelCount; + + /** The sample format of the buffer provided to the stream callback, + a_ReadStream() or Pa_WriteStream(). It may be any of the formats described + by the PaSampleFormat enumeration. + */ + PaSampleFormat sampleFormat; + + /** The desired latency in seconds. Where practical, implementations should + configure their latency based on these parameters, otherwise they may + choose the closest viable latency instead. Unless the suggested latency + is greater than the absolute upper limit for the device implementations + shouldround the suggestedLatency up to the next practial value - ie to + provide an equal or higher latency than suggestedLatency whereever possibe. + Actual latency values for an open stream may be retrieved using the + inputLatency and outputLatency fields of the PaStreamInfo structure + returned by Pa_GetStreamInfo(). + @see default*Latency in PaDeviceInfo, *Latency in PaStreamInfo + */ + PaTime suggestedLatency; + + /** An optional pointer to a host api specific data structure + containing additional information for device setup and/or stream processing. + hostApiSpecificStreamInfo is never required for correct operation, + if not used it should be set to NULL. + */ + void *hostApiSpecificStreamInfo; + +} PaStreamParameters; + + +/** Return code for Pa_IsFormatSupported indicating success. */ +#define paFormatIsSupported (0) + +/** Determine whether it would be possible to open a stream with the specified + parameters. + + @param inputParameters A structure that describes the input parameters used to + open a stream. The suggestedLatency field is ignored. See PaStreamParameters + for a description of these parameters. inputParameters must be NULL for + output-only streams. + + @param outputParameters A structure that describes the output parameters used + to open a stream. The suggestedLatency field is ignored. See PaStreamParameters + for a description of these parameters. outputParameters must be NULL for + input-only streams. + + @param sampleRate The required sampleRate. For full-duplex streams it is the + sample rate for both input and output + + @return Returns 0 if the format is supported, and an error code indicating why + the format is not supported otherwise. The constant paFormatIsSupported is + provided to compare with the return value for success. + + @see paFormatIsSupported, PaStreamParameters +*/ +PaError Pa_IsFormatSupported( const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate ); + + + +/* Streaming types and functions */ + + +/** + A single PaStream can provide multiple channels of real-time + streaming audio input and output to a client application. A stream + provides access to audio hardware represented by one or more + PaDevices. Depending on the underlying Host API, it may be possible + to open multiple streams using the same device, however this behavior + is implementation defined. Portable applications should assume that + a PaDevice may be simultaneously used by at most one PaStream. + + Pointers to PaStream objects are passed between PortAudio functions that + operate on streams. + + @see Pa_OpenStream, Pa_OpenDefaultStream, Pa_OpenDefaultStream, Pa_CloseStream, + Pa_StartStream, Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive, + Pa_GetStreamTime, Pa_GetStreamCpuLoad + +*/ +typedef void PaStream; + + +/** Can be passed as the framesPerBuffer parameter to Pa_OpenStream() + or Pa_OpenDefaultStream() to indicate that the stream callback will + accept buffers of any size. +*/ +#define paFramesPerBufferUnspecified (0) + + +/** Flags used to control the behavior of a stream. They are passed as + parameters to Pa_OpenStream or Pa_OpenDefaultStream. Multiple flags may be + ORed together. + + @see Pa_OpenStream, Pa_OpenDefaultStream + @see paNoFlag, paClipOff, paDitherOff, paNeverDropInput, + paPrimeOutputBuffersUsingStreamCallback, paPlatformSpecificFlags +*/ +typedef unsigned long PaStreamFlags; + +/** @see PaStreamFlags */ +#define paNoFlag ((PaStreamFlags) 0) + +/** Disable default clipping of out of range samples. + @see PaStreamFlags +*/ +#define paClipOff ((PaStreamFlags) 0x00000001) + +/** Disable default dithering. + @see PaStreamFlags +*/ +#define paDitherOff ((PaStreamFlags) 0x00000002) + +/** Flag requests that where possible a full duplex stream will not discard + overflowed input samples without calling the stream callback. This flag is + only valid for full duplex callback streams and only when used in combination + with the paFramesPerBufferUnspecified (0) framesPerBuffer parameter. Using + this flag incorrectly results in a paInvalidFlag error being returned from + Pa_OpenStream and Pa_OpenDefaultStream. + + @see PaStreamFlags, paFramesPerBufferUnspecified +*/ +#define paNeverDropInput ((PaStreamFlags) 0x00000004) + +/** Call the stream callback to fill initial output buffers, rather than the + default behavior of priming the buffers with zeros (silence). This flag has + no effect for input-only and blocking read/write streams. + + @see PaStreamFlags +*/ +#define paPrimeOutputBuffersUsingStreamCallback ((PaStreamFlags) 0x00000008) + +/** A mask specifying the platform specific bits. + @see PaStreamFlags +*/ +#define paPlatformSpecificFlags ((PaStreamFlags)0xFFFF0000) + +/** + Timing information for the buffers passed to the stream callback. +*/ +typedef struct PaStreamCallbackTimeInfo{ + PaTime inputBufferAdcTime; + PaTime currentTime; + PaTime outputBufferDacTime; +} PaStreamCallbackTimeInfo; + + +/** + Flag bit constants for the statusFlags to PaStreamCallback. + + @see paInputUnderflow, paInputOverflow, paOutputUnderflow, paOutputOverflow, + paPrimingOutput +*/ +typedef unsigned long PaStreamCallbackFlags; + +/** In a stream opened with paFramesPerBufferUnspecified, indicates that + input data is all silence (zeros) because no real data is available. In a + stream opened without paFramesPerBufferUnspecified, it indicates that one or + more zero samples have been inserted into the input buffer to compensate + for an input underflow. + @see PaStreamCallbackFlags +*/ +#define paInputUnderflow ((PaStreamCallbackFlags) 0x00000001) + +/** In a stream opened with paFramesPerBufferUnspecified, indicates that data + prior to the first sample of the input buffer was discarded due to an + overflow, possibly because the stream callback is using too much CPU time. + Otherwise indicates that data prior to one or more samples in the + input buffer was discarded. + @see PaStreamCallbackFlags +*/ +#define paInputOverflow ((PaStreamCallbackFlags) 0x00000002) + +/** Indicates that output data (or a gap) was inserted, possibly because the + stream callback is using too much CPU time. + @see PaStreamCallbackFlags +*/ +#define paOutputUnderflow ((PaStreamCallbackFlags) 0x00000004) + +/** Indicates that output data will be discarded because no room is available. + @see PaStreamCallbackFlags +*/ +#define paOutputOverflow ((PaStreamCallbackFlags) 0x00000008) + +/** Some of all of the output data will be used to prime the stream, input + data may be zero. + @see PaStreamCallbackFlags +*/ +#define paPrimingOutput ((PaStreamCallbackFlags) 0x00000010) + +/** + Allowable return values for the PaStreamCallback. + @see PaStreamCallback +*/ +typedef enum PaStreamCallbackResult +{ + paContinue=0, + paComplete=1, + paAbort=2 +} PaStreamCallbackResult; + + +/** + Functions of type PaStreamCallback are implemented by PortAudio clients. + They consume, process or generate audio in response to requests from an + active PortAudio stream. + + @param input and @param output are arrays of interleaved samples, + the format, packing and number of channels used by the buffers are + determined by parameters to Pa_OpenStream(). + + @param frameCount The number of sample frames to be processed by + the stream callback. + + @param timeInfo The time in seconds when the first sample of the input + buffer was received at the audio input, the time in seconds when the first + sample of the output buffer will begin being played at the audio output, and + the time in seconds when the stream callback was called. + See also Pa_GetStreamTime() + + @param statusFlags Flags indicating whether input and/or output buffers + have been inserted or will be dropped to overcome underflow or overflow + conditions. + + @param userData The value of a user supplied pointer passed to + Pa_OpenStream() intended for storing synthesis data etc. + + @return + The stream callback should return one of the values in the + PaStreamCallbackResult enumeration. To ensure that the callback continues + to be called, it should return paContinue (0). Either paComplete or paAbort + can be returned to finish stream processing, after either of these values is + returned the callback will not be called again. If paAbort is returned the + stream will finish as soon as possible. If paComplete is returned, the stream + will continue until all buffers generated by the callback have been played. + This may be useful in applications such as soundfile players where a specific + duration of output is required. However, it is not necessary to utilise this + mechanism as Pa_StopStream(), Pa_AbortStream() or Pa_CloseStream() can also + be used to stop the stream. The callback must always fill the entire output + buffer irrespective of its return value. + + @see Pa_OpenStream, Pa_OpenDefaultStream + + @note With the exception of Pa_GetStreamCpuLoad() it is not permissable to call + PortAudio API functions from within the stream callback. +*/ +typedef int PaStreamCallback( + const void *input, void *output, + unsigned long frameCount, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *userData ); + + +/** Opens a stream for either input, output or both. + + @param stream The address of a PaStream pointer which will receive + a pointer to the newly opened stream. + + @param inputParameters A structure that describes the input parameters used by + the opened stream. See PaStreamParameters for a description of these parameters. + inputParameters must be NULL for output-only streams. + + @param outputParameters A structure that describes the output parameters used by + the opened stream. See PaStreamParameters for a description of these parameters. + outputParameters must be NULL for input-only streams. + + @param sampleRate The desired sampleRate. For full-duplex streams it is the + sample rate for both input and output + + @param framesPerBuffer The number of frames passed to the stream callback + function, or the preferred block granularity for a blocking read/write stream. + The special value paFramesPerBufferUnspecified (0) may be used to request that + the stream callback will recieve an optimal (and possibly varying) number of + frames based on host requirements and the requested latency settings. + Note: With some host APIs, the use of non-zero framesPerBuffer for a callback + stream may introduce an additional layer of buffering which could introduce + additional latency. PortAudio guarantees that the additional latency + will be kept to the theoretical minimum however, it is strongly recommended + that a non-zero framesPerBuffer value only be used when your algorithm + requires a fixed number of frames per stream callback. + + @param streamFlags Flags which modify the behaviour of the streaming process. + This parameter may contain a combination of flags ORed together. Some flags may + only be relevant to certain buffer formats. + + @param streamCallback A pointer to a client supplied function that is responsible + for processing and filling input and output buffers. If this parameter is NULL + the stream will be opened in 'blocking read/write' mode. In blocking mode, + the client can receive sample data using Pa_ReadStream and write sample data + using Pa_WriteStream, the number of samples that may be read or written + without blocking is returned by Pa_GetStreamReadAvailable and + Pa_GetStreamWriteAvailable respectively. + + @param userData A client supplied pointer which is passed to the stream callback + function. It could for example, contain a pointer to instance data necessary + for processing the audio buffers. This parameter is ignored if streamCallback + is NULL. + + @return + Upon success Pa_OpenStream() returns paNoError and places a pointer to a + valid PaStream in the stream argument. The stream is inactive (stopped). + If a call to Pa_OpenStream() fails, a non-zero error code is returned (see + PaError for possible error codes) and the value of stream is invalid. + + @see PaStreamParameters, PaStreamCallback, Pa_ReadStream, Pa_WriteStream, + Pa_GetStreamReadAvailable, Pa_GetStreamWriteAvailable +*/ +PaError Pa_OpenStream( PaStream** stream, + const PaStreamParameters *inputParameters, + const PaStreamParameters *outputParameters, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamFlags streamFlags, + PaStreamCallback *streamCallback, + void *userData ); + + +/** A simplified version of Pa_OpenStream() that opens the default input + and/or output devices. + + @param stream The address of a PaStream pointer which will receive + a pointer to the newly opened stream. + + @param numInputChannels The number of channels of sound that will be supplied + to the stream callback or returned by Pa_ReadStream. It can range from 1 to + the value of maxInputChannels in the PaDeviceInfo record for the default input + device. If 0 the stream is opened as an output-only stream. + + @param numOutputChannels The number of channels of sound to be delivered to the + stream callback or passed to Pa_WriteStream. It can range from 1 to the value + of maxOutputChannels in the PaDeviceInfo record for the default output dvice. + If 0 the stream is opened as an output-only stream. + + @param sampleFormat The sample format of both the input and output buffers + provided to the callback or passed to and from Pa_ReadStream and Pa_WriteStream. + sampleFormat may be any of the formats described by the PaSampleFormat + enumeration. + + @param sampleRate Same as Pa_OpenStream parameter of the same name. + @param framesPerBuffer Same as Pa_OpenStream parameter of the same name. + @param streamCallback Same as Pa_OpenStream parameter of the same name. + @param userData Same as Pa_OpenStream parameter of the same name. + + @return As for Pa_OpenStream + + @see Pa_OpenStream, PaStreamCallback +*/ +PaError Pa_OpenDefaultStream( PaStream** stream, + int numInputChannels, + int numOutputChannels, + PaSampleFormat sampleFormat, + double sampleRate, + unsigned long framesPerBuffer, + PaStreamCallback *streamCallback, + void *userData ); + + +/** Closes an audio stream. If the audio stream is active it + discards any pending buffers as if Pa_AbortStream() had been called. +*/ +PaError Pa_CloseStream( PaStream *stream ); + + +/** Functions of type PaStreamFinishedCallback are implemented by PortAudio + clients. They can be registered with a stream using the Pa_SetStreamFinishedCallback + function. Once registered they are called when the stream becomes inactive + (ie once a call to Pa_StopStream() will not block). + A stream will become inactive after the stream callback returns non-zero, + or when Pa_StopStream or Pa_AbortStream is called. For a stream providing audio + output, if the stream callback returns paComplete, or Pa_StopStream is called, + the stream finished callback will not be called until all generated sample data + has been played. + + @param userData The userData parameter supplied to Pa_OpenStream() + + @see Pa_SetStreamFinishedCallback +*/ +typedef void PaStreamFinishedCallback( void *userData ); + + +/** Register a stream finished callback function which will be called when the + stream becomes inactive. See the description of PaStreamFinishedCallback for + further details about when the callback will be called. + + @param stream a pointer to a PaStream that is in the stopped state - if the + stream is not stopped, the stream's finished callback will remain unchanged + and an error code will be returned. + + @param streamFinishedCallback a pointer to a function with the same signature + as PaStreamFinishedCallback, that will be called when the stream becomes + inactive. Passing NULL for this parameter will un-register a previously + registered stream finished callback function. + + @return on success returns paNoError, otherwise an error code indicating the cause + of the error. + + @see PaStreamFinishedCallback +*/ +PaError Pa_SetStreamFinishedCallback( PaStream *stream, PaStreamFinishedCallback* streamFinishedCallback ); + + +/** Commences audio processing. +*/ +PaError Pa_StartStream( PaStream *stream ); + + +/** Terminates audio processing. It waits until all pending + audio buffers have been played before it returns. +*/ +PaError Pa_StopStream( PaStream *stream ); + + +/** Terminates audio processing immediately without waiting for pending + buffers to complete. +*/ +PaError Pa_AbortStream( PaStream *stream ); + + +/** Determine whether the stream is stopped. + A stream is considered to be stopped prior to a successful call to + Pa_StartStream and after a successful call to Pa_StopStream or Pa_AbortStream. + If a stream callback returns a value other than paContinue the stream is NOT + considered to be stopped. + + @return Returns one (1) when the stream is stopped, zero (0) when + the stream is running or, a PaErrorCode (which are always negative) if + PortAudio is not initialized or an error is encountered. + + @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamActive +*/ +PaError Pa_IsStreamStopped( PaStream *stream ); + + +/** Determine whether the stream is active. + A stream is active after a successful call to Pa_StartStream(), until it + becomes inactive either as a result of a call to Pa_StopStream() or + Pa_AbortStream(), or as a result of a return value other than paContinue from + the stream callback. In the latter case, the stream is considered inactive + after the last buffer has finished playing. + + @return Returns one (1) when the stream is active (ie playing or recording + audio), zero (0) when not playing or, a PaErrorCode (which are always negative) + if PortAudio is not initialized or an error is encountered. + + @see Pa_StopStream, Pa_AbortStream, Pa_IsStreamStopped +*/ +PaError Pa_IsStreamActive( PaStream *stream ); + + + +/** A structure containing unchanging information about an open stream. + @see Pa_GetStreamInfo +*/ + +typedef struct PaStreamInfo +{ + /** this is struct version 1 */ + int structVersion; + + /** The input latency of the stream in seconds. This value provides the most + accurate estimate of input latency available to the implementation. It may + differ significantly from the suggestedLatency value passed to Pa_OpenStream(). + The value of this field will be zero (0.) for output-only streams. + @see PaTime + */ + PaTime inputLatency; + + /** The output latency of the stream in seconds. This value provides the most + accurate estimate of output latency available to the implementation. It may + differ significantly from the suggestedLatency value passed to Pa_OpenStream(). + The value of this field will be zero (0.) for input-only streams. + @see PaTime + */ + PaTime outputLatency; + + /** The sample rate of the stream in Hertz (samples per second). In cases + where the hardware sample rate is inaccurate and PortAudio is aware of it, + the value of this field may be different from the sampleRate parameter + passed to Pa_OpenStream(). If information about the actual hardware sample + rate is not available, this field will have the same value as the sampleRate + parameter passed to Pa_OpenStream(). + */ + double sampleRate; + +} PaStreamInfo; + + +/** Retrieve a pointer to a PaStreamInfo structure containing information + about the specified stream. + @return A pointer to an immutable PaStreamInfo structure. If the stream + parameter invalid, or an error is encountered, the function returns NULL. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @note PortAudio manages the memory referenced by the returned pointer, + the client must not manipulate or free the memory. The pointer is only + guaranteed to be valid until the specified stream is closed. + + @see PaStreamInfo +*/ +const PaStreamInfo* Pa_GetStreamInfo( PaStream *stream ); + + +/** Determine the current time for the stream according to the same clock used + to generate buffer timestamps. This time may be used for syncronising other + events to the audio stream, for example synchronizing audio to MIDI. + + @return The stream's current time in seconds, or 0 if an error occurred. + + @see PaTime, PaStreamCallback +*/ +PaTime Pa_GetStreamTime( PaStream *stream ); + + +/** Retrieve CPU usage information for the specified stream. + The "CPU Load" is a fraction of total CPU time consumed by a callback stream's + audio processing routines including, but not limited to the client supplied + stream callback. This function does not work with blocking read/write streams. + + This function may be called from the stream callback function or the + application. + + @return + A floating point value, typically between 0.0 and 1.0, where 1.0 indicates + that the stream callback is consuming the maximum number of CPU cycles possible + to maintain real-time operation. A value of 0.5 would imply that PortAudio and + the stream callback was consuming roughly 50% of the available CPU time. The + return value may exceed 1.0. A value of 0.0 will always be returned for a + blocking read/write stream, or if an error occurrs. +*/ +double Pa_GetStreamCpuLoad( PaStream* stream ); + + +/** Read samples from an input stream. The function doesn't return until + the entire buffer has been filled - this may involve waiting for the operating + system to supply the data. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @param buffer A pointer to a buffer of sample frames. The buffer contains + samples in the format specified by the inputParameters->sampleFormat field + used to open the stream, and the number of channels specified by + inputParameters->numChannels. If non-interleaved samples were requested, + buffer is a pointer to the first element of an array of non-interleaved + buffer pointers, one for each channel. + + @param frames The number of frames to be read into buffer. This parameter + is not constrained to a specific range, however high performance applications + will want to match this parameter to the framesPerBuffer parameter used + when opening the stream. + + @return On success PaNoError will be returned, or PaInputOverflowed if input + data was discarded by PortAudio after the previous call and before this call. +*/ +PaError Pa_ReadStream( PaStream* stream, + void *buffer, + unsigned long frames ); + + +/** Write samples to an output stream. This function doesn't return until the + entire buffer has been consumed - this may involve waiting for the operating + system to consume the data. + + @param stream A pointer to an open stream previously created with Pa_OpenStream. + + @param buffer A pointer to a buffer of sample frames. The buffer contains + samples in the format specified by the outputParameters->sampleFormat field + used to open the stream, and the number of channels specified by + outputParameters->numChannels. If non-interleaved samples were requested, + buffer is a pointer to the first element of an array of non-interleaved + buffer pointers, one for each channel. + + @param frames The number of frames to be written from buffer. This parameter + is not constrained to a specific range, however high performance applications + will want to match this parameter to the framesPerBuffer parameter used + when opening the stream. + + @return On success PaNoError will be returned, or paOutputUnderflowed if + additional output data was inserted after the previous call and before this + call. +*/ +PaError Pa_WriteStream( PaStream* stream, + const void *buffer, + unsigned long frames ); + + +/** Retrieve the number of frames that can be read from the stream without + waiting. + + @return Returns a non-negative value representing the maximum number of frames + that can be read from the stream without blocking or busy waiting or, a + PaErrorCode (which are always negative) if PortAudio is not initialized or an + error is encountered. +*/ +signed long Pa_GetStreamReadAvailable( PaStream* stream ); + + +/** Retrieve the number of frames that can be written to the stream without + waiting. + + @return Returns a non-negative value representing the maximum number of frames + that can be written to the stream without blocking or busy waiting or, a + PaErrorCode (which are always negative) if PortAudio is not initialized or an + error is encountered. +*/ +signed long Pa_GetStreamWriteAvailable( PaStream* stream ); + + +/* Miscellaneous utilities */ + + +/** Retrieve the size of a given sample format in bytes. + + @return The size in bytes of a single sample in the specified format, + or paSampleFormatNotSupported if the format is not supported. +*/ +PaError Pa_GetSampleSize( PaSampleFormat format ); + + +/** Put the caller to sleep for at least 'msec' milliseconds. This function is + provided only as a convenience for authors of portable code (such as the tests + and examples in the PortAudio distribution.) + + The function may sleep longer than requested so don't rely on this for accurate + musical timing. +*/ +void Pa_Sleep( long msec ); + + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* PORTAUDIO_H */ diff --git a/lib/ft2/ptt.c b/lib/ft2/ptt.c new file mode 100644 index 000000000..fdda4ff97 --- /dev/null +++ b/lib/ft2/ptt.c @@ -0,0 +1,58 @@ +#include +#include + +int ptt_(int *nport, int *ntx, int *ndtr, int *iptt) +{ + static HANDLE hFile; + static int open=0, nhold=0; + char s[10]; + int i3,i4,i5,i6,i9,i00; + + if(*nport==0) { + *iptt=*ntx; + return(0); + } + + nhold=0; + if(*nport>100) nhold=1; + + if(*ntx && (!open)) { + sprintf(s,"\\\\.\\COM%d",*nport%100); + hFile=CreateFile( + TEXT(s), + GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); + if(hFile==INVALID_HANDLE_VALUE) { + printf("PTT: Cannot open COM port %d.\n",*nport%100); + return(-1); + } + open=1; + } + + if(*ntx && open) { + if(*ndtr) + EscapeCommFunction(hFile,5); //set DTR + else + EscapeCommFunction(hFile,3); //set RTS + *iptt=1; + } + + else { + if(*ndtr) + EscapeCommFunction(hFile,6); //clear DTR + else + EscapeCommFunction(hFile,4); //clear RTS + EscapeCommFunction(hFile,9); //clear BREAK + if(nhold==0) { + i00=CloseHandle(hFile); + open=0; + } + *iptt=0; + } + return(0); +} diff --git a/lib/ft2/ptt_unix.c b/lib/ft2/ptt_unix.c new file mode 100644 index 000000000..b16380608 --- /dev/null +++ b/lib/ft2/ptt_unix.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include +#include +#include +//#include +//#include +//#include +//#include +//#include + +int lp_reset (int fd); +int lp_ptt (int fd, int onoff); + +#ifdef HAVE_SYS_STAT_H +# include +#endif +#if (defined(__unix__) || defined(unix)) && !defined(USG) +# include +#endif + +#include +/* parport functions */ + +int dev_is_parport(int fd); +int ptt_parallel(int fd, int *ntx, int *iptt); +int ptt_serial(int fd, int *ntx, int *iptt); + +int fd=-1; /* Used for both serial and parallel */ + +/* + * ptt_ + * + * generic unix PTT routine called from Fortran + * + * Inputs + * unused Unused, to satisfy old windows calling convention + * ptt_port device name serial or parallel + * ntx pointer to fortran command on or off + * iptt pointer to fortran command status on or off + * Returns - non 0 if error +*/ + +/* Tiny state machine */ +#define STATE_PORT_CLOSED 0 +#define STATE_PORT_OPEN_PARALLEL 1 +#define STATE_PORT_OPEN_SERIAL 2 + +int +ptt_(int *unused, char *ptt_port, int *ntx, int *ndtr, int *iptt) +{ + static int state=0; + char *p; + + /* In the very unlikely event of a NULL pointer, just return. + * Yes, I realise this should not be possible in WSJT. + */ + if (ptt_port == NULL) { + *iptt = *ntx; + return (0); + } + + switch (state) { + case STATE_PORT_CLOSED: + + /* Remove trailing ' ' */ + if ((p = strchr(ptt_port, ' ')) != NULL) + *p = '\0'; + + /* If all that is left is a '\0' then also just return */ + if (*ptt_port == '\0') { + *iptt = *ntx; + return(0); + } + + if ((fd = open(ptt_port, O_RDWR|O_NONBLOCK)) < 0) { + fprintf(stderr, "Can't open %s.\n", ptt_port); + return (1); + } + + if (dev_is_parport(fd)) { + state = STATE_PORT_OPEN_PARALLEL; + lp_reset(fd); + ptt_parallel(fd, ntx, iptt); + } else { + state = STATE_PORT_OPEN_SERIAL; + ptt_serial(fd, ntx, iptt); + } + break; + + case STATE_PORT_OPEN_PARALLEL: + ptt_parallel(fd, ntx, iptt); + break; + + case STATE_PORT_OPEN_SERIAL: + ptt_serial(fd, ntx, iptt); + break; + + default: + close(fd); + fd = -1; + state = STATE_PORT_CLOSED; + break; + } + return(0); +} + +/* + * ptt_serial + * + * generic serial unix PTT routine called indirectly from Fortran + * + * fd - already opened file descriptor + * ntx - pointer to fortran command on or off + * iptt - pointer to fortran command status on or off + */ + +int +ptt_serial(int fd, int *ntx, int *iptt) +{ + int control = TIOCM_RTS | TIOCM_DTR; + + if(*ntx) { + ioctl(fd, TIOCMBIS, &control); /* Set DTR and RTS */ + *iptt = 1; + } else { + ioctl(fd, TIOCMBIC, &control); + *iptt = 0; + } + return(0); +} + + +/* parport functions */ + +/* + * dev_is_parport(fd): + * + * inputs - Already open fd + * output - 1 if parallel port, 0 if not + * side effects - Unfortunately, this is platform specific. + */ + +#if defined(HAVE_LINUX_PPDEV_H) /* Linux (ppdev) */ + +int +dev_is_parport(int fd) +{ + struct stat st; + int m; + + if ((fstat(fd, &st) == -1) || + ((st.st_mode & S_IFMT) != S_IFCHR) || + (ioctl(fd, PPGETMODE, &m) == -1)) + return(0); + + return(1); +} + +#elif defined(HAVE_DEV_PPBUS_PPI_H) /* FreeBSD (ppbus/ppi) */ + +int +dev_is_parport(int fd) +{ + struct stat st; + unsigned char c; + + if ((fstat(fd, &st) == -1) || + ((st.st_mode & S_IFMT) != S_IFCHR) || + (ioctl(fd, PPISSTATUS, &c) == -1)) + return(0); + + return(1); +} + +#else /* Fallback (nothing) */ + +int +dev_is_parport(int fd) +{ + return(0); +} + +#endif +/* Linux wrapper around PPFCONTROL */ +#ifdef HAVE_LINUX_PPDEV_H +static void +parport_control (int fd, unsigned char controlbits, int values) +{ + struct ppdev_frob_struct frob; + frob.mask = controlbits; + frob.val = values; + + if (ioctl (fd, PPFCONTROL, &frob) == -1) + { + fprintf(stderr, "Parallel port PPFCONTROL"); + exit (1); + } +} +#endif + +/* FreeBSD wrapper around PPISCTRL */ +#ifdef HAVE_DEV_PPBUS_PPI_H +static void +parport_control (int fd, unsigned char controlbits, int values) +{ + unsigned char val; + + if (ioctl (fd, PPIGCTRL, &val) == -1) + { + fprintf(stderr, "Parallel port PPIGCTRL"); + exit (1); + } + + val &= ~controlbits; + val |= values; + + if (ioctl (fd, PPISCTRL, &val) == -1) + { + fprintf(stderr, "Parallel port PPISCTRL"); + exit (1); + } +} +#endif + +/* Initialise a parallel port, given open fd */ +int +lp_init (int fd) +{ +#ifdef HAVE_LINUX_PPDEV_H + int mode; +#endif + +#ifdef HAVE_LINUX_PPDEV_H + mode = PARPORT_MODE_PCSPP; + + if (ioctl (fd, PPSETMODE, &mode) == -1) + { + fprintf(stderr, "Setting parallel port mode"); + close (fd); + return(-1); + } + + if (ioctl (fd, PPEXCL, NULL) == -1) + { + fprintf(stderr, "Parallel port is already in use.\n"); + close (fd); + return(-1); + } + if (ioctl (fd, PPCLAIM, NULL) == -1) + { + fprintf(stderr, "Claiming parallel port.\n"); + fprintf(stderr, "HINT: did you unload the lp kernel module?"); + close (fd); + return(-1); + } + + /* Enable CW & PTT - /STROBE bit (pin 1) */ + parport_control (fd, PARPORT_CONTROL_STROBE, PARPORT_CONTROL_STROBE); +#endif +#ifdef HAVE_DEV_PPBUS_PPI_H + parport_control (fd, STROBE, STROBE); +#endif + lp_reset (fd); + return(0); +} + +/* release ppdev and close port */ +int +lp_free (int fd) +{ +#ifdef HAVE_LINUX_PPDEV_H + lp_reset (fd); + + /* Disable CW & PTT - /STROBE bit (pin 1) */ + parport_control (fd, PARPORT_CONTROL_STROBE, 0); + + ioctl (fd, PPRELEASE); +#endif +#ifdef HAVE_DEV_PPBUS_PPI_H + /* Disable CW & PTT - /STROBE bit (pin 1) */ + parport_control (fd, STROBE, 0); +#endif + close (fd); + return(0); +} + +/* set to a known state */ +int +lp_reset (int fd) +{ +#if defined (HAVE_LINUX_PPDEV_H) || defined (HAVE_DEV_PPBUS_PPI_H) + lp_ptt (fd, 0); +#endif + return(0); +} + +/* SSB PTT keying - /INIT bit (pin 16) (inverted) */ +int +lp_ptt (int fd, int onoff) +{ +#ifdef HAVE_LINUX_PPDEV_H + if (onoff == 1) + parport_control (fd, PARPORT_CONTROL_INIT, + PARPORT_CONTROL_INIT); + else + parport_control (fd, PARPORT_CONTROL_INIT, 0); +#endif +#ifdef HAVE_DEV_PPBUS_PPI_H + if (onoff == 1) + parport_control (fd, nINIT, + nINIT); + else + parport_control (fd, nINIT, 0); +#endif + return(0); +} + +/* + * ptt_parallel + * + * generic parallel unix PTT routine called indirectly from Fortran + * + * fd - already opened file descriptor + * ntx - pointer to fortran command on or off + * iptt - pointer to fortran command status on or off + */ + +int +ptt_parallel(int fd, int *ntx, int *iptt) +{ + if(*ntx) { + lp_ptt(fd, 1); + *iptt=1; + } else { + lp_ptt(fd, 0); + *iptt=0; + } + return(0); +} diff --git a/lib/ft4/clockit.f90 b/lib/ft4/clockit.f90 new file mode 100644 index 000000000..eb3e7d8b1 --- /dev/null +++ b/lib/ft4/clockit.f90 @@ -0,0 +1,111 @@ +subroutine clockit(dname,k) + +! Times procedure number n between a call with k=0 (tstart) and with +! k=1 (tstop). Accumulates sums of these times in array ut (user time). +! Also traces all calls (for debugging purposes) if limtrace.gt.0 + + character*8 dname,name(50),space,ename + character*16 sname + character*512 data_dir,fname + logical first,on(50) + real ut(50),ut0(50),dut(50),tt(2) + integer ncall(50),nlevel(50),nparent(50) + integer onlevel(0:10) + data first/.true./,eps/0.000001/,ntrace/0/ + data level/0/,nmax/0/,space/' '/ + data limtrace/0/,lu/29/,ntimer/1/ +! data limtrace/1000000/,lu/29/,ntimer/1/ + save + + if(ntimer.eq.0) return + if(lu.lt.1) lu=6 + if(k.gt.1) go to 40 !Check for "all done" (k>1) + onlevel(0)=0 + + do n=1,nmax !Check for existing name + if(name(n).eq.dname) go to 20 + enddo + + nmax=nmax+1 !This is a new one + n=nmax + ncall(n)=0 + on(n)=.false. + ut(n)=eps + name(n)=dname + +20 if(k.eq.0) then !Get start times (k=0) + if(on(n)) print*,'Error in timer: ',dname,' already on.' + level=level+1 !Increment the level + on(n)=.true. + ut0(n)=etime(tt) + ncall(n)=ncall(n)+1 + if(ncall(n).gt.1.and.nlevel(n).ne.level) then + nlevel(n)=-1 + else + nlevel(n)=level + endif + nparent(n)=onlevel(level-1) + onlevel(level)=n + + else if(k.eq.1) then !Get stop times and accumulate sums. (k=1) + if(on(n)) then + on(n)=.false. + ut1=etime(tt) + ut(n)=ut(n)+ut1-ut0(n) + endif + level=level-1 + endif + + ntrace=ntrace+1 + if(ntrace.lt.limtrace) write(28,1020) ntrace,dname,k,level,nparent(n) +1020 format(i8,': ',a8,3i5) + return + +! Write out the timer statistics + +40 open(lu,file=trim(fname),status='unknown') + write(lu,1040) +1040 format(/' name time frac dtime', & + ' dfrac calls level parent'/73('-')) + + if(k.gt.100) then + ndiv=k-100 + do i=1,nmax + ncall(i)=ncall(i)/ndiv + ut(i)=ut(i)/ndiv + enddo + endif + + total=ut(1) + sum=0. + sumf=0. + do i=1,nmax + dut(i)=ut(i) + do j=i,nmax + if(nparent(j).eq.i) dut(i)=dut(i)-ut(j) + enddo + utf=ut(i)/total + dutf=dut(i)/total + sum=sum+dut(i) + sumf=sumf+dutf + kk=nlevel(i) + sname=space(1:kk)//name(i)//space(1:8-kk) + ename=space + if(i.ge.2) ename=name(nparent(i)) + write(lu,1060) float(i),sname,ut(i),utf,dut(i),dutf, & + ncall(i),nlevel(i),ename +1060 format(f4.0,a16,2(f10.2,f6.2),i7,i5,2x,a8) + enddo + + write(lu,1070) sum,sumf +1070 format(/36x,f10.2,f6.2) + close(lu) + return + + entry clockit2(data_dir) + l1=index(data_dir,char(0))-1 + if(l1.ge.1) data_dir(l1+1:l1+1)='/' + fname=data_dir(1:l1+1)//'clockit.out' + return + +end subroutine clockit diff --git a/lib/ft4/ft4_baseline.f90 b/lib/ft4/ft4_baseline.f90 new file mode 100644 index 000000000..85a60d9ec --- /dev/null +++ b/lib/ft4/ft4_baseline.f90 @@ -0,0 +1,49 @@ +subroutine ft4_baseline(s,nfa,nfb,sbase) + +! Fit baseline to spectrum +! Input: s(npts) Linear scale in power +! Output: sbase(npts) Baseline + + include 'ft4_params.f90' + implicit real*8 (a-h,o-z) + real*4 s(NH1) + real*4 sbase(NH1) + real*4 base + real*8 x(1000),y(1000),a(5) + data nseg/10/,npct/10/ + + df=12000.0/NFFT1 !5.21 Hz + ia=max(nint(200.0/df),nfa) + ib=min(NH1,nfb) + do i=ia,ib + s(i)=10.0*log10(s(i)) !Convert to dB scale + enddo + + nterms=5 + nlen=(ib-ia+1)/nseg !Length of test segment + i0=(ib-ia+1)/2 !Midpoint + k=0 + do n=1,nseg !Loop over all segments + ja=ia + (n-1)*nlen + jb=ja+nlen-1 + call pctile(s(ja),nlen,npct,base) !Find lowest npct of points + do i=ja,jb + if(s(i).le.base) then + if (k.lt.1000) k=k+1 !Save all "lower envelope" points + x(k)=i-i0 + y(k)=s(i) + endif + enddo + enddo + kz=k + a=0. + call polyfit(x,y,y,kz,nterms,0,a,chisqr) !Fit a low-order polynomial + do i=ia,ib + t=i-i0 + sbase(i)=a(1)+t*(a(2)+t*(a(3)+t*(a(4)+t*(a(5))))) + 0.65 +! write(51,3051) i*df,s(i),sbase(i) +!3051 format(3f12.3) + sbase(i)=10**(sbase(i)/10.0) + enddo + return +end subroutine ft4_baseline diff --git a/lib/ft4/ft4_downsample.f90 b/lib/ft4/ft4_downsample.f90 new file mode 100644 index 000000000..bbe53a2a2 --- /dev/null +++ b/lib/ft4/ft4_downsample.f90 @@ -0,0 +1,48 @@ +subroutine ft4_downsample(dd,newdata,f0,c) + + include 'ft4_params.f90' + parameter (NFFT2=NMAX/NDOWN) + real dd(NMAX) + complex c(0:NMAX/NDOWN-1) + complex c1(0:NFFT2-1) + complex cx(0:NMAX/2) + real x(NMAX), window(0:NFFT2-1) + equivalence (x,cx) + logical first, newdata + data first/.true./ + save first,window,x + + df=12000.0/NMAX + baud=12000.0/NSPS + if(first) then + bw_transition = 0.5*baud + bw_flat = 4*baud + iwt = bw_transition / df + iwf = bw_flat / df + pi=4.0*atan(1.0) + window(0:iwt-1) = 0.5*(1+cos(pi*(/(i,i=iwt-1,0,-1)/)/iwt)) + window(iwt:iwt+iwf-1)=1.0 + window(iwt+iwf:2*iwt+iwf-1) = 0.5*(1+cos(pi*(/(i,i=0,iwt-1)/)/iwt)) + window(2*iwt+iwf:)=0.0 + iws = baud / df + window=cshift(window,iws) + first=.false. + endif + + if(newdata) then + x=dd + call four2a(x,NMAX,1,-1,0) !r2c FFT to freq domain + endif + i0=nint(f0/df) + c1=0. + if(i0.ge.0 .and. i0.le.NMAX/2) c1(0)=cx(i0) + do i=1,NFFT2/2 + if(i0+i.ge.0 .and. i0+i.le.NMAX/2) c1(i)=cx(i0+i) + if(i0-i.ge.0 .and. i0-i.le.NMAX/2) c1(NFFT2-i)=cx(i0-i) + enddo + c1=c1*window/NFFT2 + call four2a(c1,NFFT2,1,1,1) !c2c FFT back to time domain + c=c1(0:NMAX/NDOWN-1) + + return +end subroutine ft4_downsample diff --git a/lib/ft4/ft4_params.f90 b/lib/ft4/ft4_params.f90 new file mode 100644 index 000000000..43abc573a --- /dev/null +++ b/lib/ft4/ft4_params.f90 @@ -0,0 +1,16 @@ +! FT4 +! LDPC(174,91) code, four 4x4 Costas arrays for sync, ramp-up and ramp-down symbols + +parameter (KK=91) !Information bits (77 + CRC14) +parameter (ND=87) !Data symbols +parameter (NS=16) !Sync symbols +parameter (NN=NS+ND) !Sync and data symbols (103) +parameter (NN2=NS+ND+2) !Total channel symbols (105) +parameter (NSPS=576) !Samples per symbol at 12000 S/s +parameter (NZ=NSPS*NN) !Sync and Data samples (59328) +parameter (NZ2=NSPS*NN2) !Total samples in shaped waveform (60480) +parameter (NMAX=21*3456) !Samples in iwave (72576) +parameter (NFFT1=2304, NH1=NFFT1/2) !Length of FFTs for symbol spectra +parameter (NSTEP=NSPS) !Coarse time-sync step size +parameter (NHSYM=(NMAX-NFFT1)/NSTEP) !Number of symbol spectra (1/4-sym steps) +parameter (NDOWN=18) !Downsample factor diff --git a/lib/ft4/ft4sim.f90 b/lib/ft4/ft4sim.f90 new file mode 100644 index 000000000..959cf423c --- /dev/null +++ b/lib/ft4/ft4sim.f90 @@ -0,0 +1,153 @@ +program ft4sim + +! Generate simulated signals for experimental "FT4" mode + + use wavhdr + use packjt77 + include 'ft4_params.f90' !Set various constants + parameter (NWAVE=NN*NSPS) + parameter (NZZ=21*3456) !72576 + type(hdr) h !Header for .wav file + character arg*12,fname*17 + character msg37*37,msgsent37*37 + character c77*77 + complex c0(0:NZZ-1) + complex c(0:NZZ-1) + real wave(NZZ) + real dphi(0:NZZ-1) + real pulse(3*NSPS) + integer itone(NN) + integer*1 msgbits(77) + integer*2 iwave(NZZ) !Generated full-length waveform + integer icos4(4) + data icos4/0,1,3,2/ + +! Get command-line argument(s) + nargs=iargc() + if(nargs.ne.7) then + print*,'Usage: ft4sim "message" f0 DT fdop del nfiles snr' + print*,'Examples: ft4sim "CQ W9XYZ EN37" 1500 0.0 0.1 1.0 10 -15' + print*,' ft4sim "K1ABC W9XYZ R 539 WI" 1500 0.0 0.1 1.0 10 -15' + go to 999 + endif + call getarg(1,msg37) !Message to be transmitted + call getarg(2,arg) + read(arg,*) f0 !Frequency (only used for single-signal) + call getarg(3,arg) + read(arg,*) xdt !Time offset from nominal (s) + call getarg(4,arg) + read(arg,*) fspread !Watterson frequency spread (Hz) + call getarg(5,arg) + read(arg,*) delay !Watterson delay (ms) + call getarg(6,arg) + read(arg,*) nfiles !Number of files + call getarg(7,arg) + read(arg,*) snrdb !SNR_2500 + + nfiles=abs(nfiles) + twopi=8.0*atan(1.0) + fs=12000.0 !Sample rate (Hz) + dt=1.0/fs !Sample interval (s) + hmod=1.0 !Modulation index (0.5 is MSK, 1.0 is FSK) + tt=NSPS*dt !Duration of symbols (s) + baud=1.0/tt !Keying rate (baud) + txt=NZ2*dt !Transmission length (s) + + bandwidth_ratio=2500.0/(fs/2.0) + sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb) + if(snrdb.gt.90.0) sig=1.0 + + ! Source-encode, then get itone() + i3=-1 + n3=-1 + call pack77(msg37,i3,n3,c77) + read(c77,'(77i1)') msgbits + call genft4(msg37,0,msgsent37,msgbits,itone) + write(*,*) + write(*,'(a9,a37,3x,a7,i1,a1,i1)') 'Message: ',msgsent37,'i3.n3: ',i3,'.',n3 + write(*,1000) f0,xdt,txt,snrdb +1000 format('f0:',f9.3,' DT:',f6.2,' TxT:',f6.1,' SNR:',f6.1) + write(*,*) + if(i3.eq.1) then + write(*,*) ' mycall hiscall hisgrid' + write(*,'(28i1,1x,i1,1x,28i1,1x,i1,1x,i1,1x,15i1,1x,3i1)') msgbits(1:77) + else + write(*,'(a14)') 'Message bits: ' + write(*,'(77i1)') msgbits + endif + write(*,*) + write(*,'(a17)') 'Channel symbols: ' + write(*,'(76i1)') itone + write(*,*) + + call sgran() + +! The filtered frequency pulse + do i=1,3*NSPS + tt=(i-1.5*NSPS)/real(NSPS) + pulse(i)=gfsk_pulse(1.0,tt) + enddo + +! Define the instantaneous frequency waveform + dphi_peak=twopi*hmod/real(NSPS) + dphi=0.0 + do j=1,NN + ib=(j-1)*NSPS + ie=ib+3*NSPS-1 + dphi(ib:ie)=dphi(ib:ie)+dphi_peak*pulse*itone(j) + enddo + + phi=0.0 + c0=0.0 + dphi=dphi+twopi*f0*dt +! do j=0,NMAX-1 !### ??? ### + do j=0,(NN+2)*NSPS-1 + c0(j)=cmplx(cos(phi),sin(phi)) + phi=mod(phi+dphi(j),twopi) + enddo + + c0(0:NSPS-1)=c0(0:NSPS-1)*(1.0-cos(twopi*(/(i,i=0,NSPS-1)/)/(2.0*NSPS)) )/2.0 + c0((NN+1)*NSPS:(NN+2)*NSPS-1)=c0((NN+1)*NSPS:(NN+2)*NSPS-1)*(1.0+cos(twopi*(/(i,i=0,NSPS-1)/)/(2.0*NSPS) ))/2.0 + c0((NN+2)*NSPS:)=0. + + k=nint((xdt+0.5)/dt)-NSPS + c0=cshift(c0,-k) + if(k.gt.0) c0(0:k-1)=0.0 + if(k.lt.0) c0(NZZ+k:NZZ-1)=0.0 + + do ifile=1,nfiles + c=c0 + if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c,NZZ,NWAVE,fs,delay,fspread) + c=sig*c + wave=real(c) + peak=maxval(abs(wave)) + nslots=1 + + if(snrdb.lt.90) then + do i=1,NZZ !Add gaussian noise at specified SNR + xnoise=gran() + wave(i)=wave(i) + xnoise + enddo + endif + + gain=100.0 + if(snrdb.lt.90.0) then + wave=gain*wave + else + datpk=maxval(abs(wave)) + fac=32766.9/datpk + wave=fac*wave + endif + if(any(abs(wave).gt.32767.0)) print*,"Warning - data will be clipped." + iwave=nint(wave) + h=default_header(12000,NZZ) + write(fname,1102) ifile +1102 format('000000_',i6.6,'.wav') + open(10,file=fname,status='unknown',access='stream') + write(10) h,iwave !Save to *.wav file + close(10) + write(*,1110) ifile,xdt,f0,snrdb,fname +1110 format(i4,f7.2,f8.2,f7.1,2x,a17) + enddo + +999 end program ft4sim diff --git a/lib/ft4/ft4sim_mult.f90 b/lib/ft4/ft4sim_mult.f90 new file mode 100644 index 000000000..d93978e5f --- /dev/null +++ b/lib/ft4/ft4sim_mult.f90 @@ -0,0 +1,103 @@ +program ft4sim_mult + +! Generate simulated signals for experimental "FT4" mode + + use wavhdr + use packjt77 + include 'ft4_params.f90' !FT4 protocol constants + parameter (NWAVE=NN*NSPS) + parameter (NZZ=72576) !Length of .wav file (21*3456) + type(hdr) h !Header for .wav file + character arg*12,fname*17,cjunk*4 + character msg37*37,msgsent37*37,c77*77 + complex cwave0((NN+2)*NSPS) + real wave0((NN+2)*NSPS) + real wave(NZZ) + real tmp(NZZ) + integer itone(NN) + integer*1 msgbits(77) + integer*2 iwave(NZZ) !Generated full-length waveform + +! Get command-line argument(s) + nargs=iargc() + if(nargs.ne.2) then + print*,'Usage: ft4sim_mult nsigs nfiles' + print*,'Example: ft4sim_mult 20 8 ' + go to 999 + endif + call getarg(1,arg) + read(arg,*) nsigs !Number of signals + call getarg(2,arg) + read(arg,*) nfiles !Number of files + + twopi=8.0*atan(1.0) + fs=12000.0 !Sample rate (Hz) + dt=1.0/fs !Sample interval (s) + hmod=1.0 !Modulation index (0.5 is MSK, 1.0 is FSK) + tt=NSPS*dt !Duration of unsmoothed symbols (s) + baud=1.0/tt !Keying rate (baud) + txt=NZ*dt !Transmission length (s) without ramp up/down + bandwidth_ratio=2500.0/(fs/2.0) + txt=NN*NSPS/12000.0 + open(10,file='messages.txt',status='old',err=998) + + do ifile=1,nfiles +1 read(10,1001,end=999) cjunk,n +1001 format(a4,i2) + if(cjunk.ne.'File' .or. n.ne.ifile) go to 1 + wave=0. + write(fname,1002) ifile +1002 format('000000_',i6.6,'.wav') + + do isig=1,nsigs + read(10,1003,end=100) cjunk,isnr,xdt0,ifreq,msg37 +1003 format(a4,30x,i3,f5.1,i5,1x,a37) + if(cjunk.eq.'File') go to 100 + if(isnr.lt.-17) isnr=-17 + f0=ifreq*960.0/576.0 + call random_number(r) + xdt=r-0.5 +! Source-encode, then get itone() + i3=-1 + n3=-1 + call pack77(msg37,i3,n3,c77) + call genft4(msg37,0,msgsent37,msgbits,itone) + nwave0=(NN+2)*NSPS + icmplx=0 + call gen_ft4wave(itone,NN,NSPS,12000.0,f0,cwave0,wave0,icmplx,nwave0) + + k0=nint((xdt+0.5)/dt) + if(k0.lt.1) k0=1 + tmp(:k0-1)=0.0 + tmp(k0:k0+nwave0-1)=wave0 + tmp(k0+nwave0:)=0.0 + + ! Insert this signal into wave() array + sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*isnr) + wave=wave + sig*tmp + write(*,1100) fname(1:13),isig,isnr,xdt,nint(f0),msg37 +1100 format(a13,i4,i5,f5.1,i6,2x,a37) + enddo ! isig + +100 backspace 10 + + do i=1,NZZ !Add gaussian noise at specified SNR + xnoise=gran() + wave(i)=wave(i) + xnoise + enddo + + gain=30.0 + wave=gain*wave + if(any(abs(wave).gt.32767.0)) print*,"Warning - data will be clipped." + iwave=nint(wave) + h=default_header(12000,NZZ) + open(12,file=fname,status='unknown',access='stream') + write(12) h,iwave !Save to *.wav file + close(12) + print*,' ' + enddo ! ifile + go to 999 + +998 print*,'Cannot open file "messages.txt"' + +999 end program ft4sim_mult diff --git a/lib/ft4/gen_ft4wave.f90 b/lib/ft4/gen_ft4wave.f90 new file mode 100644 index 000000000..823993612 --- /dev/null +++ b/lib/ft4/gen_ft4wave.f90 @@ -0,0 +1,66 @@ +subroutine gen_ft4wave(itone,nsym,nsps,fsample,f0,cwave,wave,icmplx,nwave) + + real wave(nwave) + complex cwave(nwave) + real pulse(6912) !576*4*3 + real dphi(0:250000-1) + integer itone(nsym) + logical first + data first/.true./ + save pulse,first,twopi,dt,hmod + + if(first) then + twopi=8.0*atan(1.0) + dt=1.0/fsample + hmod=1.0 +! Compute the smoothed frequency-deviation pulse + do i=1,3*nsps + tt=(i-1.5*nsps)/real(nsps) + pulse(i)=gfsk_pulse(1.0,tt) + enddo + first=.false. + endif + +! Compute the smoothed frequency waveform. +! Length = (nsym+2)*nsps samples, zero-padded + dphi_peak=twopi*hmod/real(nsps) + dphi=0.0 + do j=1,nsym + ib=(j-1)*nsps + ie=ib+3*nsps-1 + dphi(ib:ie) = dphi(ib:ie) + dphi_peak*pulse(1:3*nsps)*itone(j) + enddo + +! Calculate and insert the audio waveform + phi=0.0 + dphi = dphi + twopi*f0*dt !Shift frequency up by f0 + wave=0. + if(icmplx.eq.1) cwave=0. + k=0 + do j=0,nwave-1 + k=k+1 + if(icmplx.eq.0) then + wave(k)=sin(phi) + else + cwave(k)=cmplx(cos(phi),sin(phi)) + endif + phi=mod(phi+dphi(j),twopi) + enddo + +! Compute the ramp-up and ramp-down symbols + if(icmplx.eq.0) then + wave(1:nsps)=wave(1:nsps) * & + (1.0-cos(twopi*(/(i,i=0,nsps-1)/)/(2.0*nsps)))/2.0 + k1=(nsym+1)*nsps+1 + wave(k1:k1+nsps-1)=wave(k1:k1+nsps-1) * & + (1.0+cos(twopi*(/(i,i=0,nsps-1)/)/(2.0*nsps)))/2.0 + else + cwave(1:nsps)=cwave(1:nsps) * & + (1.0-cos(twopi*(/(i,i=0,nsps-1)/)/(2.0*nsps)))/2.0 + k1=(nsym+1)*nsps+1 + cwave(k1:k1+nsps-1)=cwave(k1:k1+nsps-1) * & + (1.0+cos(twopi*(/(i,i=0,nsps-1)/)/(2.0*nsps)))/2.0 + endif + + return +end subroutine gen_ft4wave diff --git a/lib/ft4/genft4.f90 b/lib/ft4/genft4.f90 new file mode 100644 index 000000000..66e70a612 --- /dev/null +++ b/lib/ft4/genft4.f90 @@ -0,0 +1,90 @@ +subroutine genft4(msg0,ichk,msgsent,msgbits,i4tone) + +! Encode an FT4 message +! Input: +! - msg0 requested message to be transmitted +! - ichk if ichk=1, return only msgsent +! - msgsent message as it will be decoded +! - i4tone array of audio tone values, {0,1,2,3} + +! Frame structure: +! s16 + 87symbols + 2 ramp up/down = 105 total channel symbols +! r1 + s4 + d29 + s4 + d29 + s4 + d29 + s4 + r1 + +! Message duration: TxT = 105*576/12000 = 5.04 s + +! use iso_c_binding, only: c_loc,c_size_t + + use packjt77 + include 'ft4_params.f90' + character*37 msg0 + character*37 message !Message to be generated + character*37 msgsent !Message as it will be received + character*77 c77 + integer*4 i4tone(NN),itmp(ND) + integer*1 codeword(2*ND) + integer*1 msgbits(77),rvec(77) + integer icos4a(4),icos4b(4),icos4c(4),icos4d(4) + logical unpk77_success + data icos4a/0,1,3,2/ + data icos4b/1,0,2,3/ + data icos4c/2,3,1,0/ + data icos4d/3,2,0,1/ + data rvec/0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,0,1,1,0, & + 1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,1,1,0,0,1,0,1, & + 0,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,0,1/ + message=msg0 + + do i=1, 37 + if(ichar(message(i:i)).eq.0) then + message(i:37)=' ' + exit + endif + enddo + do i=1,37 !Strip leading blanks + if(message(1:1).ne.' ') exit + message=message(i+1:) + enddo + + i3=-1 + n3=-1 + call pack77(message,i3,n3,c77) + call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent + + if(ichk.eq.1) go to 999 + read(c77,'(77i1)',err=1) msgbits + if(unpk77_success) go to 2 +1 msgbits=0 + itone=0 + msgsent='*** bad message *** ' + go to 999 + +entry get_ft4_tones_from_77bits(msgbits,i4tone) + +2 msgbits=mod(msgbits+rvec,2) + call encode174_91(msgbits,codeword) + +! Grayscale mapping: +! bits tone +! 00 0 +! 01 1 +! 11 2 +! 10 3 + + do i=1,ND + is=codeword(2*i)+2*codeword(2*i-1) + if(is.le.1) itmp(i)=is + if(is.eq.2) itmp(i)=3 + if(is.eq.3) itmp(i)=2 + enddo + + i4tone(1:4)=icos4a + i4tone(5:33)=itmp(1:29) + i4tone(34:37)=icos4b + i4tone(38:66)=itmp(30:58) + i4tone(67:70)=icos4c + i4tone(71:99)=itmp(59:87) + i4tone(100:103)=icos4d + +999 return +end subroutine genft4 diff --git a/lib/ft4/get_ft4_bitmetrics.f90 b/lib/ft4/get_ft4_bitmetrics.f90 new file mode 100644 index 000000000..eba86a418 --- /dev/null +++ b/lib/ft4/get_ft4_bitmetrics.f90 @@ -0,0 +1,114 @@ +subroutine get_ft4_bitmetrics(cd,bitmetrics,badsync) + + include 'ft4_params.f90' + parameter (NSS=NSPS/NDOWN,NDMAX=NMAX/NDOWN) + complex cd(0:NN*NSS-1) + complex cs(0:3,NN) + complex csymb(NSS) + integer icos4a(0:3),icos4b(0:3),icos4c(0:3),icos4d(0:3) + integer graymap(0:3) + integer ip(1) + logical one(0:255,0:7) ! 256 4-symbol sequences, 8 bits + logical first + logical badsync + real bitmetrics(2*NN,3) + real s2(0:255) + real s4(0:3,NN) + + data icos4a/0,1,3,2/ + data icos4b/1,0,2,3/ + data icos4c/2,3,1,0/ + data icos4d/3,2,0,1/ + data graymap/0,1,3,2/ + data first/.true./ + save first,one + + if(first) then + one=.false. + do i=0,255 + do j=0,7 + if(iand(i,2**j).ne.0) one(i,j)=.true. + enddo + enddo + first=.false. + endif + + do k=1,NN + i1=(k-1)*NSS + csymb=cd(i1:i1+NSS-1) + call four2a(csymb,NSS,1,-1,1) + cs(0:3,k)=csymb(1:4) + s4(0:3,k)=abs(csymb(1:4)) + enddo + +! Sync quality check + is1=0 + is2=0 + is3=0 + is4=0 + badsync=.false. + do k=1,4 + ip=maxloc(s4(:,k)) + if(icos4a(k-1).eq.(ip(1)-1)) is1=is1+1 + ip=maxloc(s4(:,k+33)) + if(icos4b(k-1).eq.(ip(1)-1)) is2=is2+1 + ip=maxloc(s4(:,k+66)) + if(icos4c(k-1).eq.(ip(1)-1)) is3=is3+1 + ip=maxloc(s4(:,k+99)) + if(icos4d(k-1).eq.(ip(1)-1)) is4=is4+1 + enddo + nsync=is1+is2+is3+is4 !Number of correct hard sync symbols, 0-16 + if(nsync .lt. 8) then + badsync=.true. + return + endif + + do nseq=1,3 !Try coherent sequences of 1, 2, and 4 symbols + if(nseq.eq.1) nsym=1 + if(nseq.eq.2) nsym=2 + if(nseq.eq.3) nsym=4 + nt=2**(2*nsym) + do ks=1,NN-nsym+1,nsym !87+16=103 symbols. + amax=-1.0 + do i=0,nt-1 + i1=i/64 + i2=iand(i,63)/16 + i3=iand(i,15)/4 + i4=iand(i,3) + if(nsym.eq.1) then + s2(i)=abs(cs(graymap(i4),ks)) + elseif(nsym.eq.2) then + s2(i)=abs(cs(graymap(i3),ks)+cs(graymap(i4),ks+1)) + elseif(nsym.eq.4) then + s2(i)=abs(cs(graymap(i1),ks ) + & + cs(graymap(i2),ks+1) + & + cs(graymap(i3),ks+2) + & + cs(graymap(i4),ks+3) & + ) + else + print*,"Error - nsym must be 1, 2, or 4." + endif + enddo + ipt=1+(ks-1)*2 + if(nsym.eq.1) ibmax=1 + if(nsym.eq.2) ibmax=3 + if(nsym.eq.4) ibmax=7 + do ib=0,ibmax + bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - & + maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib)) + if(ipt+ib.gt.2*NN) cycle + bitmetrics(ipt+ib,nseq)=bm + enddo + enddo + enddo + + bitmetrics(205:206,2)=bitmetrics(205:206,1) + bitmetrics(201:204,3)=bitmetrics(201:204,2) + bitmetrics(205:206,3)=bitmetrics(205:206,1) + + call normalizebmet(bitmetrics(:,1),2*NN) + call normalizebmet(bitmetrics(:,2),2*NN) + call normalizebmet(bitmetrics(:,3),2*NN) + return + +end subroutine get_ft4_bitmetrics diff --git a/lib/ft4/getcandidates4.f90 b/lib/ft4/getcandidates4.f90 new file mode 100644 index 000000000..3f62e8141 --- /dev/null +++ b/lib/ft4/getcandidates4.f90 @@ -0,0 +1,83 @@ +subroutine getcandidates4(dd,fa,fb,syncmin,nfqso,maxcand,savg,candidate, & + ncand,sbase) + + include 'ft4_params.f90' + real s(NH1,NHSYM) + real savg(NH1),savsm(NH1) + real sbase(NH1) + real x(NFFT1) + real window(NFFT1) + complex cx(0:NH1) + real candidate(2,maxcand),candidatet(2,maxcand) + real dd(NMAX) + equivalence (x,cx) + logical first + data first/.true./ + save first,window + + if(first) then + first=.false. + pi=4.0*atan(1.) + window=0. + call nuttal_window(window,NFFT1) + endif + +! Compute symbol spectra, stepping by NSTEP steps. + savg=0. + df=12000.0/NFFT1 + fac=1.0/300.0 + do j=1,NHSYM + ia=(j-1)*NSTEP + 1 + ib=ia+NFFT1-1 + if(ib.gt.NMAX) exit + x=fac*dd(ia:ib)*window + call four2a(x,NFFT1,1,-1,0) !r2c FFT + s(1:NH1,j)=abs(cx(1:NH1))**2 + savg=savg + s(1:NH1,j) !Average spectrum + enddo + savg=savg/NHSYM + savsm=0. + do i=8,NH1-7 + savsm(i)=sum(savg(i-7:i+7))/15. + enddo + + nfa=fa/df + if(nfa.lt.nint(200.0/df)) nfa=nint(200.0/df) + nfb=fb/df + if(nfb.gt.nint(4910.0/df)) nfb=nint(4910.0/df) + call ft4_baseline(savg,nfa,nfb,sbase) + if(any(sbase(nfa:nfb).le.0)) return + savsm(nfa:nfb)=savsm(nfa:nfb)/sbase(nfa:nfb) + f_offset = -1.5*12000.0/NSPS + ncand=0 + candidatet=0 + do i=nfa+1,nfb-1 + if(savsm(i).ge.savsm(i-1) .and. savsm(i).ge.savsm(i+1) .and. & + savsm(i).ge.syncmin) then + den=savsm(i-1)-2*savsm(i)+savsm(i+1) + del=0. + if(den.ne.0.0) del=0.5*(savsm(i-1)-savsm(i+1))/den + fpeak=(i+del)*df+f_offset + if(fpeak.lt.200.0 .or. fpeak.gt.4910.0) cycle + speak=savsm(i) - 0.25*(savsm(i-1)-savsm(i+1))*del + ncand=ncand+1 + candidatet(1,ncand)=fpeak + candidatet(2,ncand)=speak + if(ncand.eq.maxcand) exit + endif + enddo + candidate=0 + nq=count(abs(candidatet(1,1:ncand)-nfqso).le.20.0) + n1=1 + n2=nq+1 + do i=1,ncand + if(abs(candidatet(1,i)-nfqso).le.20.0) then + candidate(1:2,n1)=candidatet(1:2,i) + n1=n1+1 + else + candidate(1:2,n2)=candidatet(1:2,i) + n2=n2+1 + endif + enddo +return +end subroutine getcandidates4 diff --git a/lib/ft4/messages.txt b/lib/ft4/messages.txt new file mode 100644 index 000000000..16329fceb --- /dev/null +++ b/lib/ft4/messages.txt @@ -0,0 +1,162 @@ +File 1 +190106_000015 7.080 Rx FT8 -15 0.2 178 N1TRK N4FKH 569 VA +190106_000015 7.080 Rx FT8 -13 -0.1 253 N1TRK KB7RUQ 539 UT +190106_000015 7.080 Rx FT8 10 0.2 389 W0ZF N3LFC RR73 +190106_000015 7.080 Rx FT8 -10 0.1 450 PY4AZ KF7YED 559 MT +190106_000015 7.080 Rx FT8 -3 0.2 507 N1TRK WA4DYD 559 GA +190106_000015 7.080 Rx FT8 14 0.2 689 KB0VHA KA1YQC R 539 MA +190106_000015 7.080 Rx FT8 -5 0.1 984 W9JA N9OY RR73 +190106_000015 7.080 Rx FT8 -12 0.1 1123 VA2CZ K8GNG RR73 +190106_000015 7.080 Rx FT8 2 0.1 1240 CQ RU K7RL CN88 +190106_000015 7.080 Rx FT8 -11 0.5 1293 K4ZMW K7VZ RR73 +190106_000015 7.080 Rx FT8 2 0.1 1387 WD9IGY KX1X 73 +190106_000015 7.080 Rx FT8 -10 0.1 1536 CQ RU W0FRC DM79 +190106_000015 7.080 Rx FT8 -2 0.1 1635 K4SQC VE3RX 549 ON +190106_000030 7.080 Rx FT8 -11 0.2 1745 CQ RU K1LOG FN56 +190106_000030 7.080 Rx FT8 3 0.8 1798 WD5DAX WS4WW 73 +190106_000030 7.080 Rx FT8 12 0.1 1895 DJ6GI KG4W 73 +190106_000030 7.080 Rx FT8 -14 0.2 2119 KF7YED KF5ZNQ 549 TX +190106_000030 7.080 Rx FT8 -5 0.1 336 CQ RU AB5XS EM12 +190106_000030 7.080 Rx FT8 0 0.0 1415 W3KIT AA8SW RR73 +190106_000030 7.080 Rx FT8 -13 0.3 1540 NI6G W7DRW 579 AZ +190106_000030 7.080 Rx FT8 -10 0.1 312 SHIFT W9JA +190106_000030 7.080 Rx FT8 -16 0.1 1447 W7BOB KJ7G 549 WA +File 2 +190106_000045 7.080 Rx FT8 -9 0.1 178 N1TRK N4FKH 569 VA +190106_000045 7.080 Rx FT8 -9 -0.1 253 N1TRK KB7RUQ RR73 +190106_000045 7.080 Rx FT8 -8 0.1 336 CQ RU AB5XS EM12 +190106_000045 7.080 Rx FT8 16 0.3 689 KB0VHA KA1YQC R 539 MA +190106_000045 7.080 Rx FT8 -3 0.1 984 CQ RU N9OY EN43 +190106_000045 7.080 Rx FT8 -10 0.1 1146 K1JT WB4HXE 559 GA +190106_000045 7.080 Rx FT8 6 0.1 1240 VE3LON K7RL R 549 WA +190106_000045 7.080 Rx FT8 -1 0.1 1386 WD9IGY KX1X 73 +190106_000045 7.080 Rx FT8 -12 0.1 1536 CQ RU W0FRC DM79 +190106_000045 7.080 Rx FT8 3 0.1 1635 K4SQC VE3RX RR73 +190106_000045 7.080 Rx FT8 -5 0.1 1688 CQ RU W1QA FN32 +190106_000045 7.080 Rx FT8 1 0.8 1797 CQ RU WS4WW FM17 +190106_000045 7.080 Rx FT8 14 0.1 1895 HB9BUN KG4W R 549 VA +190106_000100 7.080 Rx FT8 -7 0.1 2002 W9TO KN3ILZ 529 PA +190106_000100 7.080 Rx FT8 -9 0.1 312 W9JA PY2APK RRR +190106_000100 7.080 Rx FT8 -12 0.1 436 NZ7P WA7JAY 589 CA +190106_000100 7.080 Rx FT8 -13 -0.1 1380 AC6BW KR9A R 559 WI +190106_000100 7.080 Rx FT8 -17 0.1 1448 W7BOB KJ7G RR73 +190106_000100 7.080 Rx FT8 -7 0.3 1540 NI6G W7DRW 569 AZ +File 3 +190106_000115 7.080 Rx FT8 -13 0.2 178 N1TRK N4FKH 569 VA +190106_000115 7.080 Rx FT8 -14 -0.1 253 N1TRK KB7RUQ RR73 +190106_000115 7.080 Rx FT8 -5 0.1 336 CQ RU AB5XS EM12 +190106_000115 7.080 Rx FT8 -7 0.1 449 NI6G KF7YED 569 MT +190106_000115 7.080 Rx FT8 14 0.2 689 KB0VHA KA1YQC 73 +190106_000115 7.080 Rx FT8 11 0.4 852 W9TO N4QWF 569 VA +190106_000115 7.080 Rx FT8 -3 0.1 984 W4EMB N9OY R 529 WI +190106_000115 7.080 Rx FT8 -14 0.1 1117 WB4FAY K7PDW 549 UT +190106_000115 7.080 Rx FT8 3 0.2 1240 VE3LON K7RL R 559 WA +190106_000115 7.080 Rx FT8 -18 0.1 1380 AC6BW KR9A R 559 WI +190106_000115 7.080 Rx FT8 4 0.1 1475 K4KCL KB4S 559 VA +190106_000130 7.080 Rx FT8 -5 0.1 1612 K1JT WB4HXE RR73 +190106_000115 7.080 Rx FT8 -1 0.1 1688 KW4RTR W1QA R 539 MA +190106_000115 7.080 Rx FT8 -15 0.2 1745 CQ RU K1LOG FN56 +190106_000115 7.080 Rx FT8 3 0.8 1798 WA1T WS4WW R 579 VA +190106_000115 7.080 Rx FT8 14 0.1 1895 HB9BUN KG4W R 549 VA +190106_000115 7.080 Rx FT8 -9 0.2 2125 CQ RU NF3R FN20 +190106_000130 7.080 Rx FT8 -8 0.4 976 AG1T K7VZ 569 AZ +190106_000130 7.080 Rx FT8 -7 0.1 1434 Z36W N4KMC 529 FL +File 4 +190106_000145 7.080 Rx FT8 -8 0.1 335 CQ RU AB5XS EM12 +190106_000145 7.080 Rx FT8 -11 0.2 388 W0ZF WW4LL 559 ME +190106_000145 7.080 Rx FT8 -10 0.1 449 NI6G KF7YED 569 MT +190106_000145 7.080 Rx FT8 10 0.3 689 CQ RU KA1YQC FN42 +190106_000145 7.080 Rx FT8 12 0.4 852 W9TO N4QWF RR73 +190106_000145 7.080 Rx FT8 -2 0.1 984 W4EMB N9OY R 529 WI +190106_000145 7.080 Rx FT8 -12 0.1 1117 WB4FAY K7PDW 549 UT +190106_000145 7.080 Rx FT8 4 0.2 1240 VE3LON K7RL 73 +190106_000145 7.080 Rx FT8 -13 0.1 1348 WW5M KO9V 559 NC +190106_000145 7.080 Rx FT8 -14 0.1 1380 AC6BW KR9A R 559 WI +190106_000145 7.080 Rx FT8 2 0.1 1475 K4KCL KB4S RR73 +190106_000145 7.080 Rx FT8 -9 0.1 1536 KC1HTT W0FRC 73 +190106_000145 7.080 Rx FT8 1 0.1 1688 KW4RTR W1QA R 539 MA +190106_000200 7.080 Rx FT8 1 0.8 1797 WA1T WS4WW R 569 VA +190106_000200 7.080 Rx FT8 15 0.1 1895 CQ RU KG4W FM17 +190106_000200 7.080 Rx FT8 -6 0.2 2125 CQ RU NF3R FN20 +190106_000200 7.080 Rx FT8 -7 0.1 311 PD8DX PY2APK 539 0081 +190106_000200 7.080 Rx FT8 -3 0.5 976 AG1T K7VZ RR73 +190106_000200 7.080 Rx FT8 -5 0.1 1432 Z36W N4KMC 529 FL +190106_000200 7.080 Rx FT8 -7 0.3 1540 N7BT W7DRW 559 AZ +190106_000200 7.080 Rx FT8 -16 0.3 2124 N3KCR ON9COP 529 0053 +190106_000200 7.080 Rx FT8 -12 0.1 1448 K2DH KJ7G 549 WA +File 5 +190106_000215 7.080 Rx FT8 11 0.1 435 K1JT WV8WA 569 WV +190106_000215 7.080 Rx FT8 -4 0.1 335 CQ RU AB5XS EM12 +190106_000215 7.080 Rx FT8 10 0.5 689 CQ RU KA1YQC FN42 +190106_000215 7.080 Rx FT8 -10 0.1 843 CQ RU AE5JH EL07 +190106_000215 7.080 Rx FT8 -3 0.1 984 W4EMB N9OY R 529 WI +190106_000215 7.080 Rx FT8 -10 0.1 1118 WB4FAY W5MO 539 TX +190106_000215 7.080 Rx FT8 -16 0.1 1170 K1JT K8GNG 569 MI +190106_000215 7.080 Rx FT8 6 0.1 1240 CQ RU K7RL CN88 +190106_000215 7.080 Rx FT8 -8 0.1 1348 WW5M KO9V RR73 +190106_000215 7.080 Rx FT8 -12 0.1 1432 Z36W N4KMC 529 FL +190106_000215 7.080 Rx FT8 2 0.1 1490 KA6BIM KB4S 529 VA +190106_000230 7.080 Rx FT8 -1 0.1 1688 CQ RU W1QA FN32 +190106_000230 7.080 Rx FT8 15 0.1 1895 DD5ZZ KG4W R 539 VA +190106_000230 7.080 Rx FT8 -8 0.2 2125 CQ RU NF3R FN20 +190106_000230 7.080 Rx FT8 -13 0.1 1380 AC6BW KR9A R 559 WI +190106_000230 7.080 Rx FT8 -4 0.1 1536 CQ RU W0FRC DM79 +190106_000230 7.080 Rx FT8 -8 0.3 1540 N7BT W7DRW 559 AZ +File 6 +190106_000245 7.080 Rx FT8 6 0.1 635 K1JT WV8WA RR73 +190106_000245 7.080 Rx FT8 -12 0.1 335 VE3RX AB5XS R 589 TX +190106_000245 7.080 Rx FT8 -16 0.1 423 WA1T PY2APK 529 0081 +190106_000245 7.080 Rx FT8 9 0.4 507 N1TRK N4QWF RR73 +190106_000245 7.080 Rx FT8 -10 0.1 869 W7BOB W3KIT 539 MD +190106_000245 7.080 Rx FT8 -7 0.1 984 W4EMB N9OY R 529 WI +190106_000245 7.080 Rx FT8 -13 0.1 1170 K1JT K8GNG 569 MI +190106_000245 7.080 Rx FT8 5 0.1 1240 W6GMT K7RL R 569 WA +190106_000245 7.080 Rx FT8 2 0.1 1490 KA6BIM KB4S 529 VA +190106_000245 7.080 Rx FT8 -1 0.1 1688 CQ RU W1QA FN32 +190106_000245 7.080 Rx FT8 1 0.7 1798 N3KCR WS4WW R 599 VA +190106_000245 7.080 Rx FT8 17 0.1 1895 DD5ZZ KG4W 73 +190106_000300 7.080 Rx FT8 -10 0.2 2125 CQ RU NF3R FN20 +190106_000300 7.080 Rx FT8 8 0.1 546 W7BOB W4DHE 539 KY +190106_000300 7.080 Rx FT8 -9 0.2 844 CQ RU AE5JH EL07 +190106_000300 7.080 Rx FT8 -5 0.1 1536 W9WLX W0FRC R 549 CO +File 7 +190106_000315 7.080 Rx FT8 -5 0.1 335 VE3RX AB5XS 73 +190106_000315 7.080 Rx FT8 -13 0.1 424 WA1T PY2APK 529 0081 +190106_000315 7.080 Rx FT8 6 0.1 545 W7BOB W4DHE 539 KY +190106_000315 7.080 Rx FT8 -7 0.4 600 K2DH K7VZ 549 AZ +190106_000315 7.080 Rx FT8 9 0.1 689 VE3LON KA1YQC 73 +190106_000315 7.080 Rx FT8 -8 0.1 869 W7BOB W3KIT 539 MD +190106_000315 7.080 Rx FT8 -1 0.1 984 W4EMB N9OY R 529 WI +190106_000315 7.080 Rx FT8 -15 -0.1 1117 WB4FAY KB7RUQ 529 UT +190106_000315 7.080 Rx FT8 7 -0.2 1240 W6GMT K7RL 73 +190106_000315 7.080 Rx FT8 -5 0.2 1581 VA3WW WA4DYD 559 GA +190106_000315 7.080 Rx FT8 -8 0.1 1688 DD5ZZ W1QA R 569 MA +190106_000315 7.080 Rx FT8 4 0.7 1798 N3KCR WS4WW 73 +190106_000315 7.080 Rx FT8 16 0.1 1895 CQ RU KG4W FM17 +190106_000315 7.080 Rx FT8 -11 0.2 2125 CQ RU NF3R FN20 +190106_000330 7.080 Rx FT8 -8 0.1 1170 K1JT K8GNG RR73 +190106_000330 7.080 Rx FT8 -13 -0.1 454 NZ7P KM7S R 549 CA +190106_000330 7.080 Rx FT8 1 0.1 941 KW4RTR KO9V 559 NC +190106_000330 7.080 Rx FT8 -16 0.3 1034 W9JA W9OY 539 FL +190106_000330 7.080 Rx FT8 -2 0.1 1240 K2DH KD2GXL 559 NY +190106_000330 7.080 Rx FT8 -5 0.1 1536 W9WLX W0FRC 73 +190106_000330 7.080 Rx FT8 -2 -0.1 918 KF6JXM W5BT 529 TX +File 8 +190106_000345 7.080 Rx FT8 -5 0.1 335 CQ RU AB5XS EM12 +190106_000345 7.080 Rx FT8 -13 0.1 423 WA1T PY2APK 529 0081 +190106_000345 7.080 Rx FT8 6 0.2 689 CQ RU KA1YQC FN42 +190106_000345 7.080 Rx FT8 -16 0.1 852 W9TO KM4LFT RR73 +190106_000345 7.080 Rx FT8 -4 -0.1 918 KF6JXM W5BT 529 TX +190106_000345 7.080 Rx FT8 2 0.1 984 W4EMB N9OY R 529 WI +190106_000345 7.080 Rx FT8 -15 0.3 1034 W9JA W9OY RR73 +190106_000345 7.080 Rx FT8 -7 0.1 1175 K2DH KD2GXL 559 NY +190106_000345 7.080 Rx FT8 6 -0.1 1240 CQ RU K7RL CN88 +190106_000345 7.080 Rx FT8 -10 0.1 1536 CQ RU W0FRC DM79 +190106_000345 7.080 Rx FT8 -7 0.2 1581 VA3WW WA4DYD RR73 +190106_000345 7.080 Rx FT8 -9 0.1 1688 DD5ZZ W1QA 73 +190106_000345 7.080 Rx FT8 17 0.1 1895 CQ RU KG4W FM17 +190106_000345 7.080 Rx FT8 -9 0.1 2002 K2DH KN3ILZ 549 PA +190106_000400 7.080 Rx FT8 -5 0.7 2052 CQ RU WS4WW FM17 +190106_000400 7.080 Rx FT8 -9 0.2 2125 NV4G NF3R R 549 PA +190106_000400 7.080 Rx FT8 -5 0.0 941 KW4RTR KO9V RR73 +190106_000400 7.080 Rx FT8 -7 0.2 1744 KC1HTT K1LOG R 569 ME diff --git a/lib/ft4/subtractft4.f90 b/lib/ft4/subtractft4.f90 new file mode 100644 index 000000000..ae104ddb3 --- /dev/null +++ b/lib/ft4/subtractft4.f90 @@ -0,0 +1,66 @@ +subroutine subtractft4(dd,itone,f0,dt) + +! Subtract an ft4 signal +! +! Measured signal : dd(t) = a(t)cos(2*pi*f0*t+theta(t)) +! Reference signal : cref(t) = exp( j*(2*pi*f0*t+phi(t)) ) +! Complex amp : cfilt(t) = LPF[ dd(t)*CONJG(cref(t)) ] +! Subtract : dd(t) = dd(t) - 2*REAL{cref*cfilt} + + use timer_module, only: timer + + parameter (NMAX=21*3456,NSPS=576,NFFT=NMAX,NFILT=1400) + parameter (NFRAME=(103+2)*NSPS) + real*4 dd(NMAX), window(-NFILT/2:NFILT/2), xjunk + complex cref,camp,cfilt,cw + integer itone(103) + logical first + data first/.true./ + common/heap8/cref(NFRAME),camp(NMAX),cfilt(NMAX),cw(NMAX),xjunk(NFRAME) + save first + + nstart=dt*12000+1-NSPS + nsym=103 + fs=12000.0 + icmplx=1 + bt=1.0 + nss=NSPS + call gen_ft4wave(itone,nsym,nss,fs,f0,cref,xjunk,icmplx,NFRAME) + camp=0. + do i=1,nframe + id=nstart-1+i + if(id.ge.1.and.id.le.NMAX) camp(i)=dd(id)*conjg(cref(i)) + enddo + + if(first) then +! Create and normalize the filter + pi=4.0*atan(1.0) + fac=1.0/float(nfft) + sum=0.0 + do j=-NFILT/2,NFILT/2 + window(j)=cos(pi*j/NFILT)**2 + sum=sum+window(j) + enddo + cw=0. + cw(1:NFILT+1)=window/sum + cw=cshift(cw,NFILT/2+1) + call four2a(cw,nfft,1,-1,1) + cw=cw*fac + first=.false. + endif + + cfilt=0.0 + cfilt(1:nframe)=camp(1:nframe) + call four2a(cfilt,nfft,1,-1,1) + cfilt(1:nfft)=cfilt(1:nfft)*cw(1:nfft) + call four2a(cfilt,nfft,1,1,1) + +! Subtract the reconstructed signal + do i=1,nframe + j=nstart+i-1 + if(j.ge.1 .and. j.le.NMAX) dd(j)=dd(j)-2*REAL(cfilt(i)*cref(i)) + enddo + + return +end subroutine subtractft4 + diff --git a/lib/ft4/sync4d.f90 b/lib/ft4/sync4d.f90 new file mode 100644 index 000000000..8d78f66aa --- /dev/null +++ b/lib/ft4/sync4d.f90 @@ -0,0 +1,96 @@ +subroutine sync4d(cd0,i0,ctwk,itwk,sync) + +! Compute sync power for a complex, downsampled FT4 signal. + + include 'ft4_params.f90' + parameter(NP=NMAX/NDOWN,NSS=NSPS/NDOWN) + complex cd0(0:NP-1) + complex csynca(2*NSS),csyncb(2*NSS),csyncc(2*NSS),csyncd(2*NSS) + complex csync2(2*NSS) + complex ctwk(2*NSS) + complex z1,z2,z3,z4 + logical first + integer icos4a(0:3),icos4b(0:3),icos4c(0:3),icos4d(0:3) + data icos4a/0,1,3,2/ + data icos4b/1,0,2,3/ + data icos4c/2,3,1,0/ + data icos4d/3,2,0,1/ + data first/.true./ + save first,twopi,csynca,csyncb,csyncc,csyncd,fac + + p(z1)=(real(z1*fac)**2 + aimag(z1*fac)**2)**0.5 !Statement function for power + + if( first ) then + twopi=8.0*atan(1.0) + k=1 + phia=0.0 + phib=0.0 + phic=0.0 + phid=0.0 + do i=0,3 + dphia=2*twopi*icos4a(i)/real(NSS) + dphib=2*twopi*icos4b(i)/real(NSS) + dphic=2*twopi*icos4c(i)/real(NSS) + dphid=2*twopi*icos4d(i)/real(NSS) + do j=1,NSS/2 + csynca(k)=cmplx(cos(phia),sin(phia)) + csyncb(k)=cmplx(cos(phib),sin(phib)) + csyncc(k)=cmplx(cos(phic),sin(phic)) + csyncd(k)=cmplx(cos(phid),sin(phid)) + phia=mod(phia+dphia,twopi) + phib=mod(phib+dphib,twopi) + phic=mod(phic+dphic,twopi) + phid=mod(phid+dphid,twopi) + k=k+1 + enddo + enddo + first=.false. + fac=1.0/(2.0*NSS) + endif + + i1=i0 !four Costas arrays + i2=i0+33*NSS + i3=i0+66*NSS + i4=i0+99*NSS + + z1=0. + z2=0. + z3=0. + z4=0. + + if(itwk.eq.1) csync2=ctwk*csynca !Tweak the frequency + z1=0. + if(i1.ge.0 .and. i1+4*NSS-1.le.NP-1) then + z1=sum(cd0(i1:i1+4*NSS-1:2)*conjg(csync2)) + elseif( i1.lt.0 ) then + npts=(i1+4*NSS-1)/2 + if(npts.le.16) then + z1=0. + else + z1=sum(cd0(0:i1+4*NSS-1:2)*conjg(csync2(2*NSS-npts:))) + endif + endif + + if(itwk.eq.1) csync2=ctwk*csyncb !Tweak the frequency + if(i2.ge.0 .and. i2+4*NSS-1.le.NP-1) z2=sum(cd0(i2:i2+4*NSS-1:2)*conjg(csync2)) + + if(itwk.eq.1) csync2=ctwk*csyncc !Tweak the frequency + if(i3.ge.0 .and. i3+4*NSS-1.le.NP-1) z3=sum(cd0(i3:i3+4*NSS-1:2)*conjg(csync2)) + + if(itwk.eq.1) csync2=ctwk*csyncd !Tweak the frequency + z4=0. + if(i4.ge.0 .and. i4+4*NSS-1.le.NP-1) then + z4=sum(cd0(i4:i4+4*NSS-1:2)*conjg(csync2)) + elseif( i4+4*NSS-1.gt.NP-1 ) then + npts=(NP-1-i4+1)/2 + if(npts.le.16) then + z4=0. + else + z4=sum(cd0(i4:i4+2*npts-1:2)*conjg(csync2(1:npts))) + endif + endif + + sync = p(z1) + p(z2) + p(z3) + p(z4) + + return +end subroutine sync4d diff --git a/lib/ft4_decode.f90 b/lib/ft4_decode.f90 new file mode 100644 index 000000000..c60ee179a --- /dev/null +++ b/lib/ft4_decode.f90 @@ -0,0 +1,466 @@ +module ft4_decode + + type :: ft4_decoder + procedure(ft4_decode_callback), pointer :: callback + contains + procedure :: decode + end type ft4_decoder + + abstract interface + subroutine ft4_decode_callback (this,sync,snr,dt,freq,decoded,nap,qual) + import ft4_decoder + implicit none + class(ft4_decoder), intent(inout) :: this + real, intent(in) :: sync + integer, intent(in) :: snr + real, intent(in) :: dt + real, intent(in) :: freq + character(len=37), intent(in) :: decoded + integer, intent(in) :: nap + real, intent(in) :: qual + end subroutine ft4_decode_callback + end interface + +contains + + subroutine decode(this,callback,iwave,nQSOProgress,nfqso, & + nutc,nfa,nfb,ndepth,lapcqonly,ncontest,mycall,hiscall) + use timer_module, only: timer + use packjt77 + include 'ft4/ft4_params.f90' + class(ft4_decoder), intent(inout) :: this + procedure(ft4_decode_callback) :: callback + parameter (NSS=NSPS/NDOWN,NDMAX=NMAX/NDOWN) + character message*37,msgsent*37 + character c77*77 + character*37 decodes(100) + character*17 cdatetime0 + character*12 mycall,hiscall + character*12 mycall0,hiscall0 + character*6 hhmmss + character*4 cqstr,cqstr0 + + complex cd2(0:NDMAX-1) !Complex waveform + complex cb(0:NDMAX-1) + complex cd(0:NN*NSS-1) !Complex waveform + complex ctwk(2*NSS),ctwk2(2*NSS,-16:16) + + real a(5) + real bitmetrics(2*NN,3) + real dd(NMAX) + real llr(2*ND),llra(2*ND),llrb(2*ND),llrc(2*ND),llrd(2*ND) + real candidate(2,100) + real savg(NH1),sbase(NH1) + + integer apbits(2*ND) + integer apmy_ru(28),aphis_fd(28) + integer*2 iwave(NMAX) !Raw received data + integer*1 message77(77),rvec(77),apmask(2*ND),cw(2*ND) + integer*1 hbits(2*NN) + integer i4tone(103) + integer nappasses(0:5) ! # of decoding passes for QSO States 0-5 + integer naptypes(0:5,4) ! nQSOProgress, decoding pass + integer mcq(29) + integer mrrr(19),m73(19),mrr73(19) + + logical nohiscall,unpk77_success + logical first, dobigfft + logical dosubtract,doosd + logical badsync + logical, intent(in) :: lapcqonly + + data first/.true./ + data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ + data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ + data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ + data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/ + data rvec/0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,0,1,1,0, & + 1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,1,1,0,0,1,0,1, & + 0,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,0,1/ + save fs,dt,tt,txt,twopi,h,first,apbits,nappasses,naptypes, & + mycall0,hiscall0,cqstr0,ctwk2 + + this%callback => callback + hhmmss=cdatetime0(8:13) + dxcall13=hiscall + mycall13=mycall + + if(first) then + fs=12000.0/NDOWN !Sample rate after downsampling + dt=1/fs !Sample interval after downsample (s) + tt=NSPS*dt !Duration of "itone" symbols (s) + txt=NZ*dt !Transmission length (s) without ramp up/down + twopi=8.0*atan(1.0) + h=1.0 + + do idf=-16,16 + a=0. + a(1)=real(idf) + ctwk=1. + call twkfreq1(ctwk,2*NSS,fs/2.0,a,ctwk2(:,idf)) + enddo + + mrrr=2*mod(mrrr+rvec(59:77),2)-1 + m73=2*mod(m73+rvec(59:77),2)-1 + mrr73=2*mod(mrr73+rvec(59:77),2)-1 + nappasses(0)=2 + nappasses(1)=2 + nappasses(2)=2 + nappasses(3)=2 + nappasses(4)=2 + nappasses(5)=3 + +! iaptype +!------------------------ +! 1 CQ ??? ??? (29 ap bits) +! 2 MyCall ??? ??? (29 ap bits) +! 3 MyCall DxCall ??? (58 ap bits) +! 4 MyCall DxCall RRR (77 ap bits) +! 5 MyCall DxCall 73 (77 ap bits) +! 6 MyCall DxCall RR73 (77 ap bits) +!******** + naptypes(0,1:4)=(/1,2,0,0/) ! Tx6 selected (CQ) + naptypes(1,1:4)=(/2,3,0,0/) ! Tx1 + naptypes(2,1:4)=(/2,3,0,0/) ! Tx2 + naptypes(3,1:4)=(/3,6,0,0/) ! Tx3 + naptypes(4,1:4)=(/3,6,0,0/) ! Tx4 + naptypes(5,1:4)=(/3,1,2,0/) ! Tx5 + + mycall0='' + hiscall0='' + cqstr0='' + first=.false. + endif + + if(cqstr.ne.cqstr0) then + i0=index(cqstr,' ') + if(i0.le.1) then + message='CQ A1AA AA01' + else + message='CQ '//cqstr(1:i0-1)//' A1AA AA01' + endif + i3=-1 + n3=-1 + call pack77(message,i3,n3,c77) + call unpack77(c77,1,msgsent,unpk77_success) + read(c77,'(29i1)') mcq + mcq=2*mod(mcq+rvec(1:29),2)-1 + cqstr0=cqstr + endif + + l1=index(mycall,char(0)) + if(l1.ne.0) mycall(l1:)=" " + l1=index(hiscall,char(0)) + if(l1.ne.0) hiscall(l1:)=" " + if(mycall.ne.mycall0 .or. hiscall.ne.hiscall0) then + apbits=0 + apbits(1)=99 + apbits(30)=99 + apmy_ru=0 + aphis_fd=0 + + if(len(trim(mycall)) .lt. 3) go to 10 + + nohiscall=.false. + hiscall0=hiscall + if(len(trim(hiscall0)).lt.3) then + hiscall0=mycall ! use mycall for dummy hiscall - mycall won't be hashed. + nohiscall=.true. + endif + message=trim(mycall)//' '//trim(hiscall0)//' RR73' + i3=-1 + n3=-1 + call pack77(message,i3,n3,c77) + call unpack77(c77,1,msgsent,unpk77_success) + if(i3.ne.1 .or. (message.ne.msgsent) .or. .not.unpk77_success) go to 10 + read(c77,'(77i1)') message77 + apmy_ru=2*mod(message77(1:28)+rvec(2:29),2)-1 + aphis_fd=2*mod(message77(30:57)+rvec(29:56),2)-1 + message77=mod(message77+rvec,2) + call encode174_91(message77,cw) + apbits=2*cw-1 + if(nohiscall) apbits(30)=99 + +10 continue + mycall0=mycall + hiscall0=hiscall + endif + maxcand=100 + ndecodes=0 + decodes=' ' + fa=nfa + fb=nfb + dd=iwave + +! ndepth=3: 3 passes, bp+osd +! ndepth=2: 3 passes, bp only +! ndepth=1: 1 pass, no subtraction + + max_iterations=40 + syncmin=1.2 + dosubtract=.true. + doosd=.true. + nsp=3 + if(ndepth.eq.2) then + doosd=.false. + endif + if(ndepth.eq.1) then + nsp=1 + dosubtract=.false. + doosd=.false. + endif + + do isp = 1,nsp + if(isp.eq.2) then + if(ndecodes.eq.0) exit + nd1=ndecodes + elseif(isp.eq.3) then + nd2=ndecodes-nd1 + if(nd2.eq.0) exit + endif + + candidate=0.0 + ncand=0 + call timer('getcand4',0) + call getcandidates4(dd,fa,fb,syncmin,nfqso,maxcand,savg,candidate, & + ncand,sbase) + call timer('getcand4',1) + dobigfft=.true. + do icand=1,ncand + f0=candidate(1,icand) + snr=candidate(2,icand)-1.0 + call timer('ft4_down',0) + call ft4_downsample(dd,dobigfft,f0,cd2) !Downsample to 32 Sam/Sym + call timer('ft4_down',1) + if(dobigfft) dobigfft=.false. + sum2=sum(cd2*conjg(cd2))/(real(NMAX)/real(NDOWN)) + if(sum2.gt.0.0) cd2=cd2/sqrt(sum2) +! Sample rate is now 12000/18 = 666.67 samples/second + do iseg=1,3 ! DT search is done over 3 segments + do isync=1,2 + if(isync.eq.1) then + idfmin=-12 + idfmax=12 + idfstp=3 + ibmin=-344 + ibmax=1012 + if(iseg.eq.1) then + ibmin=108 + ibmax=560 + elseif(iseg.eq.2) then + smax1=smax + ibmin=560 + ibmax=1012 + elseif(iseg.eq.3) then + ibmin=-344 + ibmax=108 + endif + ibstp=4 + else + idfmin=idfbest-4 + idfmax=idfbest+4 + idfstp=1 + ibmin=ibest-5 + ibmax=ibest+5 + ibstp=1 + endif + ibest=-1 + idfbest=0 + smax=-99. + call timer('sync4d ',0) + do idf=idfmin,idfmax,idfstp + do istart=ibmin,ibmax,ibstp + call sync4d(cd2,istart,ctwk2(:,idf),1,sync) !Find sync power + if(sync.gt.smax) then + smax=sync + ibest=istart + idfbest=idf + endif + enddo + enddo + call timer('sync4d ',1) + enddo + if(iseg.eq.1) smax1=smax + if(smax.lt.1.2) cycle + if(iseg.gt.1 .and. smax.lt.smax1) cycle + f1=f0+real(idfbest) + if( f1.le.10.0 .or. f1.ge.4990.0 ) cycle + call timer('ft4down ',0) + call ft4_downsample(dd,dobigfft,f1,cb) !Final downsample, corrected f0 + call timer('ft4down ',1) + sum2=sum(abs(cb)**2)/(real(NSS)*NN) + if(sum2.gt.0.0) cb=cb/sqrt(sum2) + cd=0. + if(ibest.ge.0) then + it=min(NDMAX-1,ibest+NN*NSS-1) + np=it-ibest+1 + cd(0:np-1)=cb(ibest:it) + else + cd(-ibest:ibest+NN*NSS-1)=cb(0:NN*NSS+2*ibest-1) + endif + call timer('bitmet ',0) + call get_ft4_bitmetrics(cd,bitmetrics,badsync) + call timer('bitmet ',1) + if(badsync) cycle + hbits=0 + where(bitmetrics(:,1).ge.0) hbits=1 + ns1=count(hbits( 1: 8).eq.(/0,0,0,1,1,0,1,1/)) + ns2=count(hbits( 67: 74).eq.(/0,1,0,0,1,1,1,0/)) + ns3=count(hbits(133:140).eq.(/1,1,1,0,0,1,0,0/)) + ns4=count(hbits(199:206).eq.(/1,0,1,1,0,0,0,1/)) + nsync_qual=ns1+ns2+ns3+ns4 + if(nsync_qual.lt. 20) cycle + + scalefac=2.83 + llra( 1: 58)=bitmetrics( 9: 66, 1) + llra( 59:116)=bitmetrics( 75:132, 1) + llra(117:174)=bitmetrics(141:198, 1) + llra=scalefac*llra + llrb( 1: 58)=bitmetrics( 9: 66, 2) + llrb( 59:116)=bitmetrics( 75:132, 2) + llrb(117:174)=bitmetrics(141:198, 2) + llrb=scalefac*llrb + llrc( 1: 58)=bitmetrics( 9: 66, 3) + llrc( 59:116)=bitmetrics( 75:132, 3) + llrc(117:174)=bitmetrics(141:198, 3) + llrc=scalefac*llrc + + apmag=maxval(abs(llra))*1.1 + npasses=3+nappasses(nQSOProgress) + if(lapcqonly) npasses=4 + if(ndepth.eq.1) npasses=3 + if(ncontest.ge.5) npasses=3 ! Don't support Fox and Hound + do ipass=1,npasses + if(ipass.eq.1) llr=llra + if(ipass.eq.2) llr=llrb + if(ipass.eq.3) llr=llrc + if(ipass.le.3) then + apmask=0 + iaptype=0 + endif + + if(ipass .gt. 3) then + llrd=llra + iaptype=naptypes(nQSOProgress,ipass-3) + if(lapcqonly) iaptype=1 + +! ncontest=0 : NONE +! 1 : NA_VHF +! 2 : EU_VHF +! 3 : FIELD DAY +! 4 : RTTY +! 5 : FOX +! 6 : HOUND +! +! Conditions that cause us to bail out of AP decoding + napwid=50 + if(ncontest.le.4 .and. iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid) ) cycle + if(iaptype.ge.2 .and. apbits(1).gt.1) cycle ! No, or nonstandard, mycall + if(iaptype.ge.3 .and. apbits(30).gt.1) cycle ! No, or nonstandard, dxcall + + if(iaptype.eq.1) then ! CQ or CQ TEST or CQ FD or CQ RU or CQ SCC + apmask=0 + apmask(1:29)=1 + llrd(1:29)=apmag*mcq(1:29) + endif + + if(iaptype.eq.2) then ! MyCall,???,??? + apmask=0 + if(ncontest.eq.0.or.ncontest.eq.1) then + apmask(1:29)=1 + llrd(1:29)=apmag*apbits(1:29) + else if(ncontest.eq.2) then + apmask(1:28)=1 + llrd(1:28)=apmag*apbits(1:28) + else if(ncontest.eq.3) then + apmask(1:28)=1 + llrd(1:28)=apmag*apbits(1:28) + else if(ncontest.eq.4) then + apmask(2:29)=1 + llrd(2:29)=apmag*apmy_ru(1:28) + endif + endif + + if(iaptype.eq.3) then ! MyCall,DxCall,??? + apmask=0 + if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2) then + apmask(1:58)=1 + llrd(1:58)=apmag*apbits(1:58) + else if(ncontest.eq.3) then ! Field Day + apmask(1:56)=1 + llrd(1:28)=apmag*apbits(1:28) + llrd(29:56)=apmag*aphis_fd(1:28) + else if(ncontest.eq.4) then ! RTTY RU + apmask(2:57)=1 + llrd(2:29)=apmag*apmy_ru(1:28) + llrd(30:57)=apmag*apbits(30:57) + endif + endif + + if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then + apmask=0 + if(ncontest.le.4) then + apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73 + if(iaptype.eq.6) llrd(1:77)=apmag*apbits(1:77) + endif + endif + + llr=llrd + endif + message77=0 + dmin=0.0 + call timer('bpdec174',0) + call bpdecode174_91(llr,apmask,max_iterations,message77, & + cw,nharderror,niterations) + call timer('bpdec174',1) + + if(doosd .and. nharderror.lt.0) then + ndeep=3 +! if(abs(nfqso-f1).le.napwid) then +! ndeep=4 +! endif + call timer('osd174_91 ',0) + call osd174_91(llr,apmask,ndeep,message77,cw,nharderror,dmin) + call timer('osd174_91 ',1) + endif + + if(sum(message77).eq.0) cycle + if( nharderror.ge.0 ) then + message77=mod(message77+rvec,2) ! remove rvec scrambling + write(c77,'(77i1)') message77(1:77) + call unpack77(c77,1,message,unpk77_success) + if(unpk77_success.and.dosubtract) then + call get_ft4_tones_from_77bits(message77,i4tone) + dt=real(ibest)/666.67 + call timer('subtract',0) + call subtractft4(dd,i4tone,f1,dt) + call timer('subtract',1) + endif + idupe=0 + do i=1,ndecodes + if(decodes(i).eq.message) idupe=1 + enddo + if(idupe.eq.1) exit + ndecodes=ndecodes+1 + decodes(ndecodes)=message + if(snr.gt.0.0) then + xsnr=10*log10(snr)-14.8 + else + xsnr=-21.0 + endif + nsnr=nint(max(-21.0,xsnr)) + xdt=ibest/666.67 - 0.5 +!write(21,'(i6.6,i5,2x,f4.1,i6,2x,a37,2x,f4.1,3i3,f5.1,i4,i4,i4)') & +! nutc,nsnr,xdt,nint(f1),message,smax,iaptype,ipass,isp,dmin,nsync_qual,nharderror,iseg + call this%callback(smax,nsnr,xdt,f1,message,iaptype,qual) + exit + endif + enddo !Sequence estimation + if(nharderror.ge.0) exit + enddo !3 DT segments + enddo !Candidate list + enddo !Subtraction loop + return + end subroutine decode + +end module ft4_decode diff --git a/lib/ft8/ft8b.f90 b/lib/ft8/ft8b.f90 index 6fbb03685..0376311f2 100644 --- a/lib/ft8/ft8b.f90 +++ b/lib/ft8/ft8b.f90 @@ -396,7 +396,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,lapcqonly, & cycle endif nbadcrc=0 ! If we get this far: valid codeword, valid (i3,n3), nonquirky message. - call get_tones_from_77bits(message77,itone) + call get_ft8_tones_from_77bits(message77,itone) if(lsubtract) call subtractft8(dd0,itone,f1,xdt) xsig=0.0 xnoi=0.0 diff --git a/lib/ft8/ft8sim.f90 b/lib/ft8/ft8sim.f90 index bbec600d4..c5dd82bb7 100644 --- a/lib/ft8/ft8sim.f90 +++ b/lib/ft8/ft8sim.f90 @@ -91,7 +91,7 @@ program ft8sim msg0=msg do ifile=1,nfiles k=nint((xdt+0.5)/dt) - ia=k + ia=max(1,k) phi=0.0 c0=0.0 do j=1,NN !Generate complex waveform @@ -105,7 +105,7 @@ program ft8sim if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c0,NMAX,NWAVE,fs,delay,fspread) c=sig*c0 - ib=k + ib=min(k,NMAX) wave=real(c) peak=maxval(abs(wave(ia:ib))) nslots=1 diff --git a/lib/ft8/ft8sim_gfsk.f90 b/lib/ft8/ft8sim_gfsk.f90 new file mode 100644 index 000000000..4cca67e48 --- /dev/null +++ b/lib/ft8/ft8sim_gfsk.f90 @@ -0,0 +1,131 @@ +program ft8sim_gfsk + +! Generate simulated "type 2" ft8 files +! Output is saved to a *.wav file. + + use wavhdr + use packjt77 + include 'ft8_params.f90' !Set various constants + parameter (NWAVE=NN*NSPS) + type(hdr) h !Header for .wav file + character arg*12,fname*17 + character msg37*37,msgsent37*37 + character c77*77 + complex c0(0:NMAX-1) + complex c(0:NMAX-1) + complex cwave(0:NWAVE-1) + real wave(NMAX) + real xjunk(NWAVE) + integer itone(NN) + integer*1 msgbits(77) + integer*2 iwave(NMAX) !Generated full-length waveform + +! Get command-line argument(s) + nargs=iargc() + if(nargs.ne.7) then + print*,'Usage: ft8sim "message" f0 DT fdop del nfiles snr' + print*,'Examples: ft8sim "K1ABC W9XYZ EN37" 1500.0 0.0 0.1 1.0 10 -18' + print*,' ft8sim "WA9XYZ/R KA1ABC/R FN42" 1500.0 0.0 0.1 1.0 10 -18' + print*,' ft8sim "K1ABC RR73; W9XYZ -11" 300 0 0 0 25 1 -10' + go to 999 + endif + call getarg(1,msg37) !Message to be transmitted + call getarg(2,arg) + read(arg,*) f0 !Frequency (only used for single-signal) + call getarg(3,arg) + read(arg,*) xdt !Time offset from nominal (s) + call getarg(4,arg) + read(arg,*) fspread !Watterson frequency spread (Hz) + call getarg(5,arg) + read(arg,*) delay !Watterson delay (ms) + call getarg(6,arg) + read(arg,*) nfiles !Number of files + call getarg(7,arg) + read(arg,*) snrdb !SNR_2500 + + nsig=1 + if(f0.lt.100.0) then + nsig=f0 + f0=1500 + endif + + nfiles=abs(nfiles) + twopi=8.0*atan(1.0) + fs=12000.0 !Sample rate (Hz) + dt=1.0/fs !Sample interval (s) + tt=NSPS*dt !Duration of symbols (s) + baud=1.0/tt !Keying rate (baud) + bw=8*baud !Occupied bandwidth (Hz) + txt=NZ*dt !Transmission length (s) + bt=2.0 + bandwidth_ratio=2500.0/(fs/2.0) + sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb) + if(snrdb.gt.90.0) sig=1.0 + txt=NN*NSPS/12000.0 + + ! Source-encode, then get itone() + i3=-1 + n3=-1 + call pack77(msg37,i3,n3,c77) + call genft8(msg37,i3,n3,msgsent37,msgbits,itone) + call gen_ft8wave(itone,NN,NSPS,bt,fs,f0,cwave,xjunk,1,NWAVE) !Generate complex cwave + + write(*,*) + write(*,'(a23,a37,3x,a7,i1,a1,i1)') 'New Style FT8 Message: ',msgsent37,'i3.n3: ',i3,'.',n3 + write(*,1000) f0,xdt,txt,snrdb,bw +1000 format('f0:',f9.3,' DT:',f6.2,' TxT:',f6.1,' SNR:',f6.1, & + ' BW:',f4.1) + write(*,*) + if(i3.eq.1) then + write(*,*) ' mycall hiscall hisgrid' + write(*,'(28i1,1x,i1,1x,28i1,1x,i1,1x,i1,1x,15i1,1x,3i1)') msgbits(1:77) + else + write(*,'(a14)') 'Message bits: ' + write(*,'(77i1)') msgbits + endif + write(*,*) + write(*,'(a17)') 'Channel symbols: ' + write(*,'(79i1)') itone + write(*,*) + + call sgran() + + msg0=msg + do ifile=1,nfiles + c0=0. + c0(0:NWAVE-1)=cwave + c0=cshift(c0,-nint((xdt+0.5)/dt)) + if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c0,NMAX,NWAVE,fs,delay,fspread) + c=sig*c0 + + wave=imag(c) + peak=maxval(abs(wave)) + nslots=1 + + if(snrdb.lt.90) then + do i=1,NMAX !Add gaussian noise at specified SNR + xnoise=gran() + wave(i)=wave(i) + xnoise + enddo + endif + + gain=100.0 + if(snrdb.lt.90.0) then + wave=gain*wave + else + datpk=maxval(abs(wave)) + fac=32766.9/datpk + wave=fac*wave + endif + if(any(abs(wave).gt.32767.0)) print*,"Warning - data will be clipped." + iwave=nint(wave) + h=default_header(12000,NMAX) + write(fname,1102) ifile +1102 format('000000_',i6.6,'.wav') + open(10,file=fname,status='unknown',access='stream') + write(10) h,iwave !Save to *.wav file + close(10) + write(*,1110) ifile,xdt,f0,snrdb,fname +1110 format(i4,f7.2,f8.2,f7.1,2x,a17) + enddo +999 end program ft8sim_gfsk diff --git a/lib/ft8/gen_ft8wave.f90 b/lib/ft8/gen_ft8wave.f90 new file mode 100644 index 000000000..10edc994e --- /dev/null +++ b/lib/ft8/gen_ft8wave.f90 @@ -0,0 +1,74 @@ +subroutine gen_ft8wave(itone,nsym,nsps,bt,fsample,f0,cwave,wave,icmplx,nwave) +! +! generate ft8 waveform using Gaussian-filtered frequency pulses. +! + + parameter(MAX_SECONDS=20) + real wave(nwave) + complex cwave(nwave) + real pulse(23040) + real dphi(0:(nsym+2)*nsps-1) + integer itone(nsym) + data ibt0/0/ + save pulse,twopi,dt,hmod,ibt0 + + ibt=nint(10*bt) + if(ibt0.ne.ibt) then + twopi=8.0*atan(1.0) + dt=1.0/fsample + hmod=1.0 +! Compute the frequency-smoothing pulse + do i=1,3*nsps + tt=(i-1.5*nsps)/real(nsps) + pulse(i)=gfsk_pulse(bt,tt) + enddo + ibt0=nint(10*bt) + endif + +! Compute the smoothed frequency waveform. +! Length = (nsym+2)*nsps samples, first and last symbols extended + dphi_peak=twopi*hmod/real(nsps) + dphi=0.0 + do j=1,nsym + ib=(j-1)*nsps + ie=ib+3*nsps-1 + dphi(ib:ie) = dphi(ib:ie) + dphi_peak*pulse(1:3*nsps)*itone(j) + enddo +! Add dummy symbols at beginning and end with tone values equal to 1st and last symbol, respectively + dphi(0:2*nsps-1)=dphi(0:2*nsps-1)+dphi_peak*itone(1)*pulse(nsps+1:3*nsps) + dphi(nsym*nsps:(nsym+2)*nsps-1)=dphi(nsym*nsps:(nsym+2)*nsps-1)+dphi_peak*itone(nsym)*pulse(1:2*nsps) + +! Calculate and insert the audio waveform + phi=0.0 + dphi = dphi + twopi*f0*dt !Shift frequency up by f0 + wave=0. + if (icmplx .ne. 0) cwave=0. ! avoid writing to memory we may not have access to + k=0 + do j=nsps,nsps+nwave-1 !Don't include dummy symbols + k=k+1 + if(icmplx.eq.0) then + wave(k)=sin(phi) + else + cwave(k)=cmplx(cos(phi),sin(phi)) + endif + phi=mod(phi+dphi(j),twopi) + enddo + +! Apply envelope shaping to the first and last symbols + nramp=nint(nsps/8.0) + if(icmplx.eq.0) then + wave(1:nramp)=wave(1:nramp) * & + (1.0-cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0 + k1=nsym*nsps-nramp+1 + wave(k1:k1+nramp-1)=wave(k1:k1+nramp-1) * & + (1.0+cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0 + else + cwave(1:nramp)=cwave(1:nramp) * & + (1.0-cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0 + k1=nsym*nsps-nramp+1 + cwave(k1:k1+nramp-1)=cwave(k1:k1+nramp-1) * & + (1.0+cos(twopi*(/(i,i=0,nramp-1)/)/(2.0*nramp)))/2.0 + endif + + return +end subroutine gen_ft8wave diff --git a/lib/ft8/genft8.f90 b/lib/ft8/genft8.f90 index 41ff546c3..a03c3e587 100644 --- a/lib/ft8/genft8.f90 +++ b/lib/ft8/genft8.f90 @@ -25,7 +25,7 @@ subroutine genft8(msg,i3,n3,msgsent,msgbits,itone) msgsent='*** bad message *** ' go to 900 -entry get_tones_from_77bits(msgbits,itone) +entry get_ft8_tones_from_77bits(msgbits,itone) 2 call encode174_91(msgbits,codeword) !Encode the test message diff --git a/lib/ft8/subtractft8.f90 b/lib/ft8/subtractft8.f90 index 1031cf2b7..ec0beea9a 100644 --- a/lib/ft8/subtractft8.f90 +++ b/lib/ft8/subtractft8.f90 @@ -11,16 +11,21 @@ subroutine subtractft8(dd,itone,f0,dt) parameter (NMAX=15*12000,NFRAME=1920*79) parameter (NFFT=NMAX,NFILT=1400) - real*4 dd(NMAX), window(-NFILT/2:NFILT/2) + real*4 dd(NMAX), window(-NFILT/2:NFILT/2), xjunk complex cref,camp,cfilt,cw integer itone(79) logical first data first/.true./ - common/heap8/cref(NFRAME),camp(NMAX),cfilt(NMAX),cw(NMAX) + common/heap8/cref(NFRAME),camp(NMAX),cfilt(NMAX),cw(NMAX),xjunk(NFRAME) save first nstart=dt*12000+1 - call genft8refsig(itone,cref,f0) + nsym=79 + nsps=1920 + fs=12000.0 + icmplx=1 + bt=2.0 + call gen_ft8wave(itone,nsym,nsps,bt,fs,f0,cref,xjunk,icmplx,NFRAME) camp=0. do i=1,nframe id=nstart-1+i diff --git a/lib/ft8/sync8.f90 b/lib/ft8/sync8.f90 index 3924f1bad..219c6ebf1 100644 --- a/lib/ft8/sync8.f90 +++ b/lib/ft8/sync8.f90 @@ -89,7 +89,12 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,s,candidate, & enddo iz=ib-ia+1 call indexx(red(ia:ib),iz,indx) - ibase=indx(nint(0.40*iz)) - 1 + ia + npctile=nint(0.40*iz) + if(npctile.lt.1) then ! something is wrong; bail out + ncand=0 + return; + endif + ibase=indx(npctile) - 1 + ia if(ibase.lt.1) ibase=1 if(ibase.gt.nh1) ibase=nh1 base=red(ibase) diff --git a/lib/ft8/watterson.f90 b/lib/ft8/watterson.f90 index a1131d7b1..7c3aa35d3 100644 --- a/lib/ft8/watterson.f90 +++ b/lib/ft8/watterson.f90 @@ -46,7 +46,11 @@ subroutine watterson(c,npts,nsig,fs,delay,fspread) endif nshift=nint(0.001*delay*fs) - c2(0:npts-1)=cshift(c(0:npts-1),nshift) + if(delay.gt.0.0) then + c2(0:npts-1)=cshift(c(0:npts-1),-nshift) !negative shifts are right shifts + else + c2(0:npts-1)=0.0 + endif sq=0. do i=0,npts-1 if(nonzero.gt.1) then diff --git a/lib/jt4_decode.f90 b/lib/jt4_decode.f90 index da0fbda68..ff0b33c4d 100644 --- a/lib/jt4_decode.f90 +++ b/lib/jt4_decode.f90 @@ -156,7 +156,7 @@ contains nfreqz=nint(dfx) call timer('sync4 ',1) - nsnr=nint(snrx) + nsnr=-26 if(sync.lt.syncmin) then if (associated (this%decode_callback)) then call this%decode_callback(nsnr,dtxz,nfreqz,.false.,csync, & @@ -166,6 +166,7 @@ contains endif ! We have achieved sync + nsnr=nint(snrsync - 22.9) decoded=blank deepmsg=blank special=' ' diff --git a/lib/jt9.f90 b/lib/jt9.f90 index ff548b46e..2e8dbd0f0 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -22,8 +22,9 @@ program jt9 !### ndepth was defined as 60001. Why??? integer :: arglen,stat,offset,remain,mode=0,flow=200,fsplit=2700, & fhigh=4000,nrxfreq=1500,ntrperiod=1,ndepth=1,nexp_decode=0 - logical :: read_files = .true., tx9 = .false., display_help = .false. - type (option) :: long_options(25) = [ & + logical :: read_files = .true., tx9 = .false., display_help = .false., & + bLowSidelobes = .false. + type (option) :: long_options(26) = [ & option ('help', .false., 'h', 'Display this help message', ''), & option ('shmem',.true.,'s','Use shared memory for sample data','KEY'), & option ('tr-period', .true., 'p', 'Tx/Rx period, default MINUTES=1', & @@ -48,10 +49,11 @@ program jt9 option ('fft-threads', .true., 'm', & 'Number of threads to process large FFTs, default THREADS=1', & 'THREADS'), & - option ('jt65', .false., '6', 'JT65 mode', ''), & - option ('jt9', .false., '9', 'JT9 mode', ''), & - option ('ft8', .false., '8', 'FT8 mode', ''), & option ('jt4', .false., '4', 'JT4 mode', ''), & + option ('ft4', .false., '5', 'FT4 mode', ''), & + option ('jt65', .false.,'6', 'JT65 mode', ''), & + option ('ft8', .false., '8', 'FT8 mode', ''), & + option ('jt9', .false., '9', 'JT9 mode', ''), & option ('qra64', .false., 'q', 'QRA64 mode', ''), & option ('sub-mode', .true., 'b', 'Sub mode, default SUBMODE=A', 'A'), & option ('depth', .true., 'd', & @@ -76,7 +78,7 @@ program jt9 nsubmode = 0 do - call getopt('hs:e:a:b:r:m:p:d:f:w:t:9864qTL:S:H:c:G:x:g:X:', & + call getopt('hs:e:a:b:r:m:p:d:f:w:t:98654qTL:S:H:c:G:x:g:X:', & long_options,c,optarg,arglen,stat,offset,remain,.true.) if (stat .ne. 0) then exit @@ -113,6 +115,8 @@ program jt9 mode = 164 case ('4') mode = 4 + case ('5') + mode = 5 case ('6') if (mode.lt.65) mode = mode + 65 case ('9') @@ -135,7 +139,7 @@ program jt9 read (optarg(:arglen), *) nexp_decode end select end do - + if (display_help .or. stat .lt. 0 & .or. (.not. read_files .and. remain .gt. 0) & .or. (read_files .and. remain .lt. 1)) then @@ -153,7 +157,7 @@ program jt9 end do go to 999 endif - + iret=fftwf_init_threads() !Initialize FFTW threading ! Default to 1 thread, but use nthreads for the big ones @@ -221,7 +225,7 @@ program jt9 endif shared_data%id2=0 !??? Why is this necessary ??? - + if(mode.eq.5) npts=21*3456 do iblk=1,npts/kstep k=iblk*kstep if(mode.eq.8 .and. k.gt.179712) exit @@ -229,7 +233,7 @@ program jt9 read(unit=wav%lun,end=3) shared_data%id2(k-kstep+1:k) go to 4 3 call timer('read_wav',1) - print*,'EOF on input file ',infile + print*,'EOF on input file ',trim(infile) exit 4 call timer('read_wav',1) nhsym=(k-2048)/kstep @@ -239,7 +243,7 @@ program jt9 ingain=0 call timer('symspec ',0) nminw=1 - call symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb, & + call symspec(shared_data,k,ntrperiod,nsps,ingain,bLowSidelobes,nminw,pxdb, & s,df3,ihsym,npts8,pxdbmax) call timer('symspec ',1) endif diff --git a/lib/nuttal_window.f90 b/lib/nuttal_window.f90 new file mode 100644 index 000000000..aa813b15d --- /dev/null +++ b/lib/nuttal_window.f90 @@ -0,0 +1,15 @@ +subroutine nuttal_window(win,n) + real win(n) + + pi=4.0*atan(1.0) + a0=0.3635819 + a1=-0.4891775; + a2=0.1365995; + a3=-0.0106411; + do i=1,n + win(i)=a0+a1*cos(2*pi*(i-1)/(n))+ & + a2*cos(4*pi*(i-1)/(n))+ & + a3*cos(6*pi*(i-1)/(n)) + enddo + return +end subroutine nuttal_window diff --git a/lib/readwav.f90 b/lib/readwav.f90 index ebc30c9a0..253690496 100644 --- a/lib/readwav.f90 +++ b/lib/readwav.f90 @@ -53,7 +53,8 @@ contains type(riff_descriptor) :: desc character(len=4) :: riff_type - open (newunit=this%lun, file=filename, access='stream', form='unformatted', status='old') + this%lun=26 + open (unit=this%lun, file=filename, access='stream',status='old') read (unit=this%lun) desc,riff_type inquire (unit=this%lun, pos=filepos) do @@ -67,5 +68,6 @@ contains end if filepos = filepos + (desc%size + 1) / 2 * 2 ! pad to even alignment end do + return end subroutine read end module readwav diff --git a/lib/rtty_spec.f90 b/lib/rtty_spec.f90 new file mode 100644 index 000000000..2ddc802f1 --- /dev/null +++ b/lib/rtty_spec.f90 @@ -0,0 +1,102 @@ +program rtty_spec + +! Generate simulated data for standard RTTY and WSJT-X modes FT8, FT4 + + use wavhdr + use packjt + parameter (NMAX=15*12000) + type(hdr) h + complex cwave(NMAX) + real wave(NMAX) + real*4 dat(NMAX) !Generated waveform + integer*2 iwave(NMAX) !Generated waveform + integer itone(680) !Channel symbols (values 0-1, 0-3, 0-7) + integer*1 msgbits(77) + character*37 msg37,msgsent37 + character*8 arg + + nargs=iargc() + if(nargs.ne.1) then + print*,'Usage: rtty_spec ' + go to 999 + endif + call getarg(1,arg) + read(arg,*) snrdb !S/N in dB (2500 hz reference BW) + + rmsdb=25. + rms=10.0**(0.05*rmsdb) + sig=10.0**(0.05*snrdb) + npts=NMAX + + do i=1,NMAX !Generate gaussian noise + dat(i)=gran() + enddo + +! Add the RTTY signal + fsample=12000.0 !Sample rate (Hz) + dt=1.0/fsample !Sample interval (s) + twopi=8.0*atan(1.0) + phi=0. + dphi=0. + j0=-1 + do i=6001,NMAX-6000 + j=nint(i*dt/0.022) + if(j.ne.j0) then + f0=1415.0 + call random_number(rr) + if(rr.gt.0.5) f0=1585.0 + dphi=twopi*f0*dt + j0=j + endif + phi=phi+dphi + if(phi.gt.twopi) phi=phi-twopi + dat(i)=dat(i) + sig*sin(phi) + enddo + +! FT8 signal (FSK) + i3=0 + n3=0 + msg37='WB9XYZ KA2ABC FN42' + call genft8(msg37,i3,n3,msgsent37,msgbits,itone) + nsym=79 + nsps=1920 + bt=99.0 + f0=3500.0 + icmplx=0 + nwave=nsym*nsps + call gen_ft8wave(itone,nsym,nsps,bt,fsample,f0,cwave,wave,icmplx,nwave) + dat(6001:6000+nwave)=dat(6001:6000+nwave) + sig*wave(1:nwave) + +! FT8 signal (GFSK) + i3=0 + n3=0 + msg37='WB9XYZ KA2ABC FN42' + call genft8(msg37,i3,n3,msgsent37,msgbits,itone) + nsym=79 + nsps=1920 + bt=2.0 + f0=4000.0 + icmplx=0 + nwave=nsym*nsps + call gen_ft8wave(itone,nsym,nsps,bt,fsample,f0,cwave,wave,icmplx,nwave) + dat(6001:6000+nwave)=dat(6001:6000+nwave) + sig*wave(1:nwave) + +! Add the FT4 signal + ichk=0 + call genft4(msg37,ichk,msgsent37,msgbits,itone) + nsym=103 + nsps=576 + f0=4500.0 + icmplx=0 + nwave=(nsym+2)*nsps + call gen_ft4wave(itone,nsym,nsps,fsample,f0,cwave,wave,icmplx,nwave) + dat(6001:6000+nwave)=dat(6001:6000+nwave) + sig*wave(1:nwave) + + h=default_header(12000,NMAX) + datmax=maxval(abs(dat)) + iwave=nint(32767.0*dat/datmax) + open(10,file='000000_000001.wav',access='stream',status='unknown') + write(10) h,iwave + close(10) + +999 end program rtty_spec diff --git a/lib/symspec.f90 b/lib/symspec.f90 index 28035d2c8..b9f5e2088 100644 --- a/lib/symspec.f90 +++ b/lib/symspec.f90 @@ -1,13 +1,14 @@ -subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s, & - df3,ihsym,npts8,pxdbmax) +subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,bLowSidelobes, & + nminw,pxdb,s,df3,ihsym,npts8,pxdbmax) ! Input: -! k pointer to the most recent new data -! ntrperiod T/R sequence length, minutes -! nsps samples per symbol, at 12000 Hz -! ndiskdat 0/1 to indicate if data from disk -! nb 0/1 status of noise blanker (off/on) -! nbslider NB setting, 0-100 +! k pointer to the most recent new data +! ntrperiod T/R sequence length, minutes +! nsps samples per symbol, at 12000 Hz +! bLowSidelobes true to use windowed FFTs +! ndiskdat 0/1 to indicate if data from disk +! nb 0/1 status of noise blanker (off/on) +! nbslider NB setting, 0-100 ! Output: ! pxdb raw power (0-90 dB) @@ -29,6 +30,7 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s, & real*4 tmp(NSMAX) complex cx(0:MAXFFT3/2) integer nch(7) + logical*1 bLowSidelobes common/spectra/syellow(NSMAX),ref(0:3456),filter(0:3456) data k0/99999999/,nfft3z/0/ @@ -48,11 +50,8 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s, & if(nfft3.ne.nfft3z) then ! Compute new window pi=4.0*atan(1.0) - width=0.25*nsps - do i=1,nfft3 - z=(i-nfft3/2)/width - w3(i)=exp(-z*z) - enddo + w3=0 + call nuttal_window(w3,nfft3) nfft3z=nfft3 endif @@ -86,10 +85,10 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s, & enddo ihsym=ihsym+1 -! xc(0:nfft3-1)=w3(1:nfft3)*xc(0:nfft3-1) !Apply window w3 - call four2a(xc,nfft3,1,-1,0) !Real-to-complex FFT + if(bLowSidelobes) xc(0:nfft3-1)=w3(1:nfft3)*xc(0:nfft3-1) !Apply window + call four2a(xc,nfft3,1,-1,0) !Real-to-complex FFT - df3=12000.0/nfft3 !JT9-1: 0.732 Hz = 0.42 * tone spacing + df3=12000.0/nfft3 !JT9: 0.732 Hz = 0.42 * tone spacing iz=min(NSMAX,nint(5000.0/df3)) fac=(1.0/nfft3)**2 do i=1,iz diff --git a/lib/wavhdr.f90 b/lib/wavhdr.f90 index b54fba787..6568c1fa6 100644 --- a/lib/wavhdr.f90 +++ b/lib/wavhdr.f90 @@ -37,17 +37,17 @@ module wavhdr subroutine set_wsjtx_wav_params(fMHz,mode,nsubmode,ntrperiod,id2) - parameter (NBANDS=23,NMODES=11) + parameter (NBANDS=23,NMODES=13) character*8 mode,modes(NMODES) integer*2 id2(4) - integer iperiod(7) + integer iperiod(8) real fband(NBANDS) data fband/0.137,0.474,1.8,3.5,5.1,7.0,10.14,14.0,18.1,21.0,24.9, & 28.0,50.0,144.0,222.0,432.0,902.0,1296.0,2304.0,3400.0, & 5760.0,10368.0,24048.0/ data modes/'Echo','FSK441','ISCAT','JT4','JT65','JT6M','JT9', & - 'JT9+JT65','JTMS','JTMSK','WSPR'/ - data iperiod/5,10,15,30,60,120,900/ + 'JT9+JT65','JTMS','JTMSK','WSPR','FT8','FT2'/ + data iperiod/5,10,15,30,60,120,900,0/ dmin=1.e30 iband=0 @@ -64,7 +64,7 @@ module wavhdr enddo ip=0 - do i=1,7 + do i=1,8 if(ntrperiod.eq.iperiod(i)) ip=i enddo @@ -78,15 +78,15 @@ module wavhdr subroutine get_wsjtx_wav_params(id2,band,mode,nsubmode,ntrperiod,ok) - parameter (NBANDS=23,NMODES=11) + parameter (NBANDS=23,NMODES=13) character*8 mode,modes(NMODES) character*6 band,bands(NBANDS) integer*2 id2(4) - integer iperiod(7) + integer iperiod(8) logical ok data modes/'Echo','FSK441','ISCAT','JT4','JT65','JT6M','JT9', & - 'JT9+JT65','JTMS','JTMSK','WSPR'/ - data iperiod/5,10,15,30,60,120,900/ + 'JT9+JT65','JTMS','JTMSK','WSPR','FT8','FT2'/ + data iperiod/5,10,15,30,60,120,900,0/ data bands/'2190m','630m','160m','80m','60m','40m','30m','20m', & '17m','15m','12m','10m','6m','2m','1.25m','70cm','33cm', & '23cm','13cm','9cm','6cm','3cm','1.25cm'/ @@ -95,7 +95,7 @@ module wavhdr if(id2(1).lt.1 .or. id2(1).gt.NBANDS) ok=.false. if(id2(2).lt.1 .or. id2(2).gt.NMODES) ok=.false. if(id2(3).lt.1 .or. id2(3).gt.8) ok=.false. - if(id2(4).lt.1 .or. id2(4).gt.7) ok=.false. + if(id2(4).lt.1 .or. id2(4).gt.8) ok=.false. if(ok) then band=bands(id2(1)) diff --git a/lib/wsprd/Makefile b/lib/wsprd/Makefile index 920407349..c8e15723f 100644 --- a/lib/wsprd/Makefile +++ b/lib/wsprd/Makefile @@ -1,11 +1,10 @@ CC = gcc -#CC = clang-3.5 FC = gfortran -CFLAGS= -I/usr/include -Wall -Wno-missing-braces -O3 -ffast-math +CFLAGS= -I/usr/include -Wall -Wno-missing-braces -Wno-unused-result -O3 -ffast-math LDFLAGS = -L/usr/lib -FFLAGS = -O2 -Wall -Wno-conversion -LIBS = -lfftw3f -lm +FFLAGS = -O2 -Wall -Wno-conversion +LIBS = -lfftw3f -lm -lgfortran # Default rules %.o: %.c $(DEPS) @@ -14,21 +13,27 @@ LIBS = -lfftw3f -lm ${FC} ${FFLAGS} -c $< %.o: %.F ${FC} ${FFLAGS} -c $< -%.o: %.f90 +%.o: %.f90 ${FC} ${FFLAGS} -c $< %.o: %.F90 ${FC} ${FFLAGS} -c $< -all: wsprd wsprsim wsprd_exp +all: wsprd wsprsim DEPS = wsprsim_utils.h wsprd_utils.h fano.h jelinek.h nhash.h -OBJS1 = wsprd.o wsprsim_utils.o wsprd_utils.o tab.o fano.o jelinek.o nhash.o + +indexx.o: ../indexx.f90 + ${FC} -o indexx.o ${FFLAGS} -c ../indexx.f90 + +OBJS1 = wsprd.o wsprsim_utils.o wsprd_utils.o tab.o fano.o jelinek.o nhash.o indexx.o osdwspr.o + wsprd: $(OBJS1) $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LIBS) OBJS2 = wsprsim.o wsprsim_utils.o wsprd_utils.o tab.o fano.o nhash.o + wsprsim: $(OBJS2) $(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LIBS) clean: - rm *.o wsprd wsprsim + $(RM) *.o wsprd wsprsim diff --git a/logbook/AD1CCty.cpp b/logbook/AD1CCty.cpp index 58ed375f6..23d34fb43 100644 --- a/logbook/AD1CCty.cpp +++ b/logbook/AD1CCty.cpp @@ -16,6 +16,7 @@ #include #include #include +#include "Configuration.hpp" #include "Radio.hpp" #include "pimpl_impl.hpp" @@ -155,14 +156,16 @@ typedef multi_index_container< class AD1CCty::impl final { public: - explicit impl () + using entity_by_id = entities_type::index::type; + + explicit impl (Configuration const * configuration) + : configuration_ {configuration} { } - Record fixup (QString call, prefix const& p) const + entity_by_id::iterator lookup_entity (QString call, prefix const& p) const { call = call.toUpper (); - using entity_by_id = entities_type::index::type; entity_by_id::iterator e; // iterator into entity set // @@ -171,23 +174,26 @@ public: if (call.startsWith ("KG4") && call.size () != 5 && call.size () != 3) { // KG4 2x1 and 2x3 calls that map to Gitmo are mainland US not Gitmo - e = entities_.project (entities_.get ().find ("K")); + return entities_.project (entities_.get ().find ("K")); } else { - e = entities_.get ().find (p.entity_id_); + return entities_.get ().find (p.entity_id_); } - + } + + Record fixup (prefix const& p, entity const& e) const + { Record result; - result.continent = e->continent_; - result.CQ_zone = e->CQ_zone_; - result.ITU_zone = e->ITU_zone_; - result.entity_name = e->name_; - result.WAE_only = e->WAE_only_; - result.latitude = e->lat_; - result.longtitude = e->long_; - result.UTC_offset = e->UTC_offset_; - result.primary_prefix = e->primary_prefix_; + result.continent = e.continent_; + result.CQ_zone = e.CQ_zone_; + result.ITU_zone = e.ITU_zone_; + result.entity_name = e.name_; + result.WAE_only = e.WAE_only_; + result.latitude = e.lat_; + result.longtitude = e.long_; + result.UTC_offset = e.UTC_offset_; + result.primary_prefix = e.primary_prefix_; // check for overrides bool ok1 {true}, ok2 {true}, ok3 {true}, ok4 {true}, ok5 {true}; @@ -220,6 +226,7 @@ public: return false; } + Configuration const * configuration_; QString path_; entities_type entities_; prefixes_type prefixes_; @@ -307,8 +314,13 @@ char const * AD1CCty::continent (Continent c) } } -AD1CCty::AD1CCty () +AD1CCty::AD1CCty (Configuration const * configuration) + : m_ {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 + // i7 reading BIG CTY.DAT. QDir dataPath {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}; m_->path_ = dataPath.exists (file_name) ? dataPath.absoluteFilePath (file_name) // user override @@ -389,7 +401,7 @@ auto AD1CCty::lookup (QString const& call) const -> Record auto p = m_->prefixes_.find (exact_search); if (p != m_->prefixes_.end () && p->exact_) { - return m_->fixup (call, *p); + return m_->fixup (*p, *m_->lookup_entity (call, *p)); } } while (search_prefix.size ()) @@ -397,9 +409,11 @@ auto AD1CCty::lookup (QString const& call) const -> Record auto p = m_->prefixes_.find (search_prefix); if (p != m_->prefixes_.end ()) { - if (!p->exact_ || call.size () == search_prefix.size ()) + impl::entity_by_id::iterator e = m_->lookup_entity (call, *p); + if ((m_->configuration_->include_WAE_entities () || !e->WAE_only_) + && (!p->exact_ || call.size () == search_prefix.size ())) { - return m_->fixup (call, *p); + return m_->fixup (*p, *e); } } search_prefix = search_prefix.left (search_prefix.size () - 1); diff --git a/logbook/AD1CCty.hpp b/logbook/AD1CCty.hpp index 37cada3e9..4a485afa9 100644 --- a/logbook/AD1CCty.hpp +++ b/logbook/AD1CCty.hpp @@ -1,17 +1,19 @@ #ifndef AD1C_CTY_HPP_ #define AD1C_CTY_HPP_ -#include #include +#include #include "pimpl_h.hpp" +class QString; +class Configuration; + // // AD1CCty - Fast access database of Jim Reisert, AD1C's, cty.dat // entity and entity override information file. // class AD1CCty final : public QObject - , private boost::noncopyable { Q_OBJECT @@ -39,7 +41,7 @@ public: QString primary_prefix; }; - explicit AD1CCty (); + explicit AD1CCty (Configuration const *); ~AD1CCty (); Record lookup (QString const& call) const; diff --git a/logbook/Multiplier.cpp b/logbook/Multiplier.cpp new file mode 100644 index 000000000..6323e4feb --- /dev/null +++ b/logbook/Multiplier.cpp @@ -0,0 +1,44 @@ +#include "Multiplier.hpp" + +#include +#include +#include +#include "models/CabrilloLog.hpp" +#include "pimpl_impl.hpp" + +class Multiplier::impl +{ +public: + impl (AD1CCty const * countries) + : countries_ {countries} + { + } + + AD1CCty const * countries_; + worked_set entities_worked_; + worked_set grids_worked_; +}; + +Multiplier::Multiplier (AD1CCty const * countries) + : m_ {countries} +{ +} + +Multiplier::~Multiplier () +{ +} + +void Multiplier::reload (CabrilloLog const * log) +{ + m_->entities_worked_ = log->unique_DXCC_entities (m_->countries_); +} + +auto Multiplier::entities_worked () const -> worked_set const& +{ + return m_->entities_worked_; +} + +auto Multiplier::grids_worked () const -> worked_set const& +{ + return m_->grids_worked_; +} diff --git a/logbook/Multiplier.hpp b/logbook/Multiplier.hpp new file mode 100644 index 000000000..2271dd775 --- /dev/null +++ b/logbook/Multiplier.hpp @@ -0,0 +1,30 @@ +#ifndef MULTIPLIER_HPP_ +#define MULTIPLIER_HPP_ + +#include +#include +#include "pimpl_h.hpp" + +class QString; +class AD1CCty; +class CabrilloLog; + +class Multiplier final + : private boost::noncopyable +{ +public: + using worked_item = QPair; + using worked_set = QSet; + + explicit Multiplier (AD1CCty const *); + ~Multiplier (); + void reload (CabrilloLog const *); + worked_set const& entities_worked () const; + worked_set const& grids_worked () const; + +private: + class impl; + pimpl m_; +}; + +#endif diff --git a/logbook/WorkedBefore.cpp b/logbook/WorkedBefore.cpp index daaf18fc7..aa65ab651 100644 --- a/logbook/WorkedBefore.cpp +++ b/logbook/WorkedBefore.cpp @@ -18,7 +18,7 @@ #include #include #include - +#include "Configuration.hpp" #include "qt_helpers.hpp" #include "pimpl_impl.hpp" @@ -332,10 +332,15 @@ namespace // will parse a record { auto const& entity = prefixes->lookup (call); + auto mode = extractField (record, "MODE").toUpper (); + if (!mode.size () || "MFSK" == mode) + { + mode = extractField (record, "SUBMODE").toUpper (); + } worked.emplace (call.toUpper () , extractField (record, "GRIDSQUARE").left (4).toUpper () // not interested in 6-digit grids , extractField (record, "BAND").toUpper () - , extractField (record, "MODE").toUpper () + , mode , entity.entity_name , entity.continent , entity.CQ_zone @@ -356,8 +361,9 @@ namespace class WorkedBefore::impl final { public: - impl () + impl (Configuration const * configuration) : path_ {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath (logFileName)} + , prefixes_ {configuration} { } @@ -374,8 +380,10 @@ public: worked_before_database_type worked_; }; -WorkedBefore::WorkedBefore () +WorkedBefore::WorkedBefore (Configuration const * configuration) + : m_ {configuration} { + Q_ASSERT (configuration); connect (&m_->loader_watcher_, &QFutureWatcher::finished, [this] () { QString error; size_t n {0}; @@ -407,9 +415,9 @@ QString const& WorkedBefore::path () const return m_->path_; } -AD1CCty const& WorkedBefore::countries () const +AD1CCty const * WorkedBefore::countries () const { - return m_->prefixes_; + return &m_->prefixes_; } bool WorkedBefore::add (QString const& call diff --git a/logbook/WorkedBefore.hpp b/logbook/WorkedBefore.hpp index 90a31813a..1aae1aca4 100644 --- a/logbook/WorkedBefore.hpp +++ b/logbook/WorkedBefore.hpp @@ -5,6 +5,7 @@ #include "AD1CCty.hpp" #include "pimpl_h.hpp" +class Configuration; class CountryDat; class QString; class QByteArray; @@ -17,7 +18,7 @@ class WorkedBefore final public: using Continent = AD1CCty::Continent; - explicit WorkedBefore (); + explicit WorkedBefore (Configuration const *); ~WorkedBefore (); Q_SLOT void reload (); @@ -28,7 +29,7 @@ public: , QByteArray const& ADIF_record); QString const& path () const; - AD1CCty const& countries () const; + AD1CCty const * countries () const; bool country_worked (QString const& call, QString const& mode, QString const& band) const; bool grid_worked (QString const& grid, QString const& mode, QString const& band) const; bool call_worked (QString const& call, QString const& mode, QString const& band) const; diff --git a/logbook/logbook.cpp b/logbook/logbook.cpp index b84b65c1a..96a8cb8e3 100644 --- a/logbook/logbook.cpp +++ b/logbook/logbook.cpp @@ -3,15 +3,25 @@ #include #include "Configuration.hpp" #include "AD1CCty.hpp" +#include "Multiplier.hpp" +#include "logbook/AD1CCty.hpp" +#include "models/CabrilloLog.hpp" +#include "models/FoxLog.hpp" #include "moc_logbook.cpp" LogBook::LogBook (Configuration const * configuration) : config_ {configuration} + , worked_before_ {configuration} { + Q_ASSERT (configuration); connect (&worked_before_, &WorkedBefore::finished_loading, this, &LogBook::finished_loading); } +LogBook::~LogBook () +{ +} + void LogBook::match (QString const& call, QString const& mode, QString const& grid, AD1CCty::Record const& looked_up, bool& callB4, @@ -22,7 +32,7 @@ void LogBook::match (QString const& call, QString const& mode, QString const& gr bool& ITUZoneB4, QString const& band) const { - if (call.length() > 0) + if (call.size() > 0) { auto const& mode_to_check = (config_ && !config_->highlight_by_mode ()) ? QString {} : mode; callB4 = worked_before_.call_worked (call, mode_to_check, band); @@ -67,46 +77,121 @@ QByteArray LogBook::QSOToADIF (QString const& hisCall, QString const& hisGrid, Q QString const& xSent, QString const& xRcvd) { QString t; - t = "" + hisCall; - t += " " + hisGrid; - t += " " + mode; - t += " " + rptSent; - t += " " + rptRcvd; + t = "" + hisCall; + t += " " + hisGrid; + if (mode != "FT4") + { + t += " " + mode; + } + else + { + t += " MFSK " + mode; + } + t += " " + rptSent; + t += " " + rptRcvd; t += " " + dateTimeOn.date().toString("yyyyMMdd"); t += " " + dateTimeOn.time().toString("hhmmss"); t += " " + dateTimeOff.date().toString("yyyyMMdd"); t += " " + dateTimeOff.time().toString("hhmmss"); - t += " " + band; - t += " " + strDialFreq; - t += " " + myCall; - t += " " + myGrid; - if(txPower!="") t += " " + txPower; - if(comments!="") t += " " + comments; - if(name!="") t += " " + name; - if(operator_call!="") t+=" " + operator_call; + t += " " + band; + t += " " + strDialFreq; + t += " " + myCall; + t += " " + myGrid; + if(txPower!="") t += " " + txPower; + if(comments!="") t += " " + comments; + if(name!="") t += " " + name; + if(operator_call!="") t+=" " + operator_call; if (xSent.size ()) { auto words = xSent.split (' ', QString::SkipEmptyParts); if (words.size () > 1) { - bool ok; - auto sn = words.back ().toUInt (&ok); - if (ok && sn) + if (words.back ().toUInt ()) { // assume last word is a serial if there are at least // two words and if it is positive numeric - t += " ' + words.back (); + t += " ' + words.back (); + } + else + { + if (words.front ().toUInt () && words.front ().size () > 3) // EU VHF contest mode + { + auto sn_text = words.front ().mid (2); + // assume first word is report+serial if there are + // at least two words and if the first word less the + // first two characters is a positive numeric + t += " ' + sn_text; + } } } } if (xRcvd.size ()) { - QString t1=""; - if(xRcvd.split(" ").size()==2) t1=xRcvd.split(" ").at(1); - if(t1.toInt()>0) { - t += " " + t1; - } else { - t += " " + t1; - } + auto words = xRcvd.split (' ', QString::SkipEmptyParts); + if (words.size () == 2) + { + if (words.at (1).toUInt ()) + { + t += " " + words.at (1); + } + else if (words.at (0).toUInt () && words.at (0).size () > 3) // EU VHF contest exchange + { + // strip report and set SRX to serial + t += " " + words.at (0).mid (2); + } + else + { + if (Configuration::SpecialOperatingActivity::FIELD_DAY == config_->special_op_id ()) + { + // include DX as an ARRL_SECT value even though it is + // not in the ADIF spec ARRL_SECT enumeration, done + // because N1MM does the same + t += " ARRL-FIELD-DAY ' + xRcvd + + " ' + + words.at (0) + " ' + words.at (1); + } + else if (Configuration::SpecialOperatingActivity::RTTY == config_->special_op_id ()) + { + t += " " + words.at (1); + } + } + } } return t.toLatin1(); } + +CabrilloLog * LogBook::contest_log () +{ + // lazy create of Cabrillo log object instance + if (!contest_log_) + { + contest_log_.reset (new CabrilloLog {config_}); + if (!multiplier_) + { + multiplier_.reset (new Multiplier {countries ()}); + } + connect (contest_log_.data (), &CabrilloLog::data_changed, [this] () { + multiplier_->reload (contest_log_.data ()); + }); + } + return contest_log_.data (); +} + +Multiplier const * LogBook::multiplier () const +{ + // lazy create of Multiplier object instance + if (!multiplier_) + { + multiplier_.reset (new Multiplier {countries ()}); + } + return multiplier_.data (); +} + +FoxLog * LogBook::fox_log () +{ + // lazy create of Fox log object instance + if (!fox_log_) + { + fox_log_.reset (new FoxLog {config_}); + } + return fox_log_.data (); +} diff --git a/logbook/logbook.h b/logbook/logbook.h index 1850aa01f..858bb64d8 100644 --- a/logbook/logbook.h +++ b/logbook/logbook.h @@ -8,12 +8,16 @@ #include #include +#include #include "WorkedBefore.hpp" class Configuration; class QByteArray; class QDateTime; +class CabrilloLog; +class Multiplier; +class FoxLog; class LogBook final : public QObject @@ -22,30 +26,38 @@ class LogBook final public: LogBook (Configuration const *); + ~LogBook (); QString const& path () const {return worked_before_.path ();} bool add (QString const& call , QString const& grid , QString const& band , QString const& mode , QByteArray const& ADIF_record); - AD1CCty const& countries () const {return worked_before_.countries ();} + AD1CCty const * countries () const {return worked_before_.countries ();} void rescan (); void match (QString const& call, QString const& mode, QString const& grid, AD1CCty::Record const&, bool& callB4, bool& countryB4, bool &gridB4, bool &continentB4, bool& CQZoneB4, bool& ITUZoneB4, QString const& currentBand = QString {}) const; - static QByteArray QSOToADIF (QString const& hisCall, QString const& hisGrid, QString const& mode, - QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, - QDateTime const& dateTimeOff, QString const& band, QString const& comments, - QString const& name, QString const& strDialFreq, QString const& myCall, - QString const& m_myGrid, QString const& m_txPower, QString const& operator_call, - QString const& xSent, QString const& xRcvd); + QByteArray QSOToADIF (QString const& hisCall, QString const& hisGrid, QString const& mode, + QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, + QDateTime const& dateTimeOff, QString const& band, QString const& comments, + QString const& name, QString const& strDialFreq, QString const& myCall, + QString const& m_myGrid, QString const& m_txPower, QString const& operator_call, + QString const& xSent, QString const& xRcvd); Q_SIGNAL void finished_loading (int worked_before_record_count, QString const& error) const; + CabrilloLog * contest_log (); + Multiplier const * multiplier () const; + FoxLog * fox_log (); + private: Configuration const * config_; WorkedBefore worked_before_; + QScopedPointer contest_log_; + QScopedPointer mutable multiplier_; + QScopedPointer fox_log_; }; #endif diff --git a/logbook/logbook.pri b/logbook/logbook.pri index fcac62524..e67cdebd3 100644 --- a/logbook/logbook.pri +++ b/logbook/logbook.pri @@ -2,10 +2,12 @@ SOURCES += \ logbook/countriesworked.cpp \ logbook/logbook.cpp \ logbook/AD1CCty.cpp \ - logbook/WorkedBefore.cpp + logbook/WorkedBefore.cpp \ + logbook/Multiplier.cpp HEADERS += \ logbook/WorkedBefore.hpp \ logbook/logbook.h \ logbook/countriesworked.h \ - logbook/AD1CCty.hpp + logbook/AD1CCty.hpp \ + logbook/Multiplier.hpp diff --git a/main.cpp b/main.cpp index fd510bffb..fc791adec 100644 --- a/main.cpp +++ b/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -91,8 +92,8 @@ 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}"); + // ### 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}"); init_random_seed (); @@ -106,6 +107,34 @@ int main(int argc, char *argv[]) ExceptionCatchingApplication a(argc, argv); try { + // + // Enable i18n + // + QTranslator translator_from_resources; + // Default translations for releases use translations stored in + // the resources file system under the Translations + // directory. These are built by the CMake build system from .ts + // files in the translations source directory. New languages are + // added by enabling the UPDATE_TRANSLATIONS CMake option and + // building with the new language added to the LANGUAGES CMake + // list variable. UPDATE_TRANSLATIONS will preserve existing + // translations but should only be set when adding new + // languages. The resulting .ts files should be checked info + // source control for translators to access and update. + translator_from_resources.load (QLocale::system (), "wsjtx", "_", ":/Translations"); + a.installTranslator (&translator_from_resources); + + QTranslator translator_from_files; + // Load any matching translation from the current directory + // using the locale name. This allows translators to easily test + // their translations by releasing (lrelease) a .qm file into + // the current directory with a suitable name + // (e.g. wsjtx_en_GB.qm), then running wsjtx to view the + // results. Either the system locale setting or the environment + // variable LANG can be used to select the target language. + translator_from_files.load (QString {"wsjtx_"} + QLocale::system ().name ()); + a.installTranslator (&translator_from_files); + setlocale (LC_NUMERIC, "C"); // ensure number forms are in // consistent format, do this after // instantiating QApplication so @@ -380,10 +409,12 @@ int main(int argc, char *argv[]) } catch (std::exception const& e) { + MessageBox::critical_message (nullptr, QApplication::translate ("main", "Fatal error"), e.what ()); std::cerr << "Error: " << e.what () << '\n'; } catch (...) { + MessageBox::critical_message (nullptr, QApplication::translate ("main", "Unexpected fatal error")); std::cerr << "Unexpected fatal error\n"; throw; // hoping the runtime might tell us more about the exception } diff --git a/models/Bands.cpp b/models/Bands.cpp index a70358fa3..e24d42965 100644 --- a/models/Bands.cpp +++ b/models/Bands.cpp @@ -55,6 +55,8 @@ namespace } } +#include "moc_Bands.cpp" + Bands::Bands (QObject * parent) : QAbstractTableModel {parent} { diff --git a/models/Bands.hpp b/models/Bands.hpp index ed625f2f1..170d4c756 100644 --- a/models/Bands.hpp +++ b/models/Bands.hpp @@ -29,6 +29,8 @@ class Bands final : public QAbstractTableModel { + Q_OBJECT + public: using Frequency = Radio::Frequency; diff --git a/models/CabrilloLog.cpp b/models/CabrilloLog.cpp index 1fee9b148..dfba3d439 100644 --- a/models/CabrilloLog.cpp +++ b/models/CabrilloLog.cpp @@ -12,6 +12,7 @@ #include #include "Configuration.hpp" #include "Bands.hpp" +#include "logbook/AD1CCty.hpp" #include "qt_db_helpers.hpp" #include "pimpl_impl.hpp" @@ -19,42 +20,109 @@ class CabrilloLog::impl final : public QSqlTableModel { public: - impl (Configuration const *); + impl (CabrilloLog *, Configuration const *); + + int columnCount (QModelIndex const& /*index */) const override + { + return QSqlTableModel::columnCount () + 1; + } + + Qt::ItemFlags flags (QModelIndex const& index) const override + { + auto flags = QSqlTableModel::flags (index); + if (index.isValid () && index.column () == columnCount (index) - 1) + { + flags = Qt::ItemIsEnabled; + } + return flags; + } + + QVariant data (QModelIndex const& model_index, int role) const override + { + QVariant value; + if (model_index.isValid () && model_index.column () == columnCount (model_index) - 1) + { // derive band column + if (Qt::DisplayRole == role) + { + value = configuration_->bands ()->find (QSqlTableModel::data (index (model_index.row (), fieldIndex ("frequency"))).toULongLong ()); + } + } + else + { + value = QSqlTableModel::data (model_index, role); + if (model_index.column () == fieldIndex ("frequency") && Qt::DisplayRole == role) + { + value = Radio::frequency_MHz_string (value.value (), 3); // kHz precision + } + else if (model_index.column () == fieldIndex ("when") + && (Qt::DisplayRole == role || Qt::EditRole == role)) + { // adjust date/time to Qt format + auto t = QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC); + if (Qt::DisplayRole == role) + { + QLocale locale; + return locale.toString (t, locale.dateFormat (QLocale::ShortFormat) + " hh:mm:ss"); + } + value = t; + } + } + return value; + } QString cabrillo_frequency_string (Radio::Frequency frequency) const; + void create_table (); + CabrilloLog * self_; Configuration const * configuration_; QSqlQuery mutable dupe_query_; QSqlQuery mutable export_query_; + bool adding_row_; }; -CabrilloLog::impl::impl (Configuration const * configuration) - : QSqlTableModel {} +CabrilloLog::impl::impl (CabrilloLog * self, Configuration const * configuration) + : self_ {self} , configuration_ {configuration} + , adding_row_ {false} { - if (!database ().tables ().contains ("cabrillo_log")) + if (!database ().tables ().contains ("cabrillo_log_v2")) { - QSqlQuery query; - SQL_error_check (query, static_cast (&QSqlQuery::exec), - "CREATE TABLE cabrillo_log (" - " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," - " frequency INTEGER NOT NULL," - " \"when\" DATETIME NOT NULL," - " call VARCHAR(20) NOT NULL," - " exchange_sent VARCHAR(32) NOT NULL," - " exchange_rcvd VARCHAR(32) NOT NULL," - " band VARCHAR(6) NOT NULL" - ")"); + create_table (); } + setEditStrategy (QSqlTableModel::OnFieldChange); + setTable ("cabrillo_log_v2"); + setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(MHz)")); + setHeaderData (fieldIndex ("mode"), Qt::Horizontal, tr ("Mode")); + setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); + setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call")); + setHeaderData (fieldIndex ("exchange_sent"), Qt::Horizontal, tr ("Sent")); + setHeaderData (fieldIndex ("exchange_rcvd"), Qt::Horizontal, tr ("Rcvd")); + setHeaderData (columnCount (QModelIndex {}) - 1, Qt::Horizontal, tr ("Band")); + + // This descending order by time is important, it makes the view + // place the latest row at the top, without this the model/view + // interactions are both sluggish and unhelpful. + setSort (fieldIndex ("when"), Qt::DescendingOrder); + + connect (this, &CabrilloLog::impl::modelReset, self_, &CabrilloLog::data_changed); + connect (this, &CabrilloLog::impl::dataChanged, [this] (QModelIndex const& tl, QModelIndex const& br) { + if (!adding_row_ && !(tl == br)) // ignore single cell changes + // as a another change for the + // whole row will follow + { + Q_EMIT self_->data_changed (); + } + }); + + SQL_error_check (*this, &QSqlTableModel::select); + SQL_error_check (dupe_query_, &QSqlQuery::prepare, "SELECT " - " COUNT(*) " + " frequency " " FROM " - " cabrillo_log " + " cabrillo_log_v2 " " WHERE " - " call = :call " - " AND band = :band"); + " call = :call "); SQL_error_check (export_query_, &QSqlQuery::prepare, "SELECT " @@ -64,32 +132,31 @@ CabrilloLog::impl::impl (Configuration const * configuration) " , call" " , exchange_rcvd" " FROM " - " cabrillo_log " + " cabrillo_log_v2 " " ORDER BY " " \"when\""); - - setEditStrategy (QSqlTableModel::OnFieldChange); - setTable ("cabrillo_log"); - setHeaderData (fieldIndex ("frequency"), Qt::Horizontal, tr ("Freq(kHz)")); - setHeaderData (fieldIndex ("when"), Qt::Horizontal, tr ("Date & Time(UTC)")); - setHeaderData (fieldIndex ("call"), Qt::Horizontal, tr ("Call")); - setHeaderData (fieldIndex ("exchange_sent"), Qt::Horizontal, tr ("Sent")); - setHeaderData (fieldIndex ("exchange_rcvd"), Qt::Horizontal, tr ("Rcvd")); - setHeaderData (fieldIndex ("band"), Qt::Horizontal, tr ("Band")); +} - // This descending order by time is important, it makes the view - // place the latest row at the top, without this the model/view - // interactions are both sluggish and unhelpful. - setSort (fieldIndex ("when"), Qt::DescendingOrder); - - SQL_error_check (*this, &QSqlTableModel::select); +void CabrilloLog::impl::create_table () +{ + QSqlQuery query; + SQL_error_check (query, static_cast (&QSqlQuery::exec), + "CREATE TABLE cabrillo_log_v2 (" + " id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," + " frequency INTEGER NOT NULL," + " mode VARCHAR(6) NOT NULL," + " \"when\" DATETIME NOT NULL," + " call VARCHAR(20) NOT NULL," + " exchange_sent VARCHAR(32) NOT NULL," + " exchange_rcvd VARCHAR(32) NOT NULL" + ")"); } // frequency here is in kHz QString CabrilloLog::impl::cabrillo_frequency_string (Radio::Frequency frequency) const { QString result; - auto band = configuration_->bands ()->find (frequency * 1000ull); + auto band = configuration_->bands ()->find (frequency); if ("1mm" == band) result = "LIGHT"; else if ("2mm" == band) result = "241G"; else if ("2.5mm" == band) result = "134G"; @@ -107,12 +174,15 @@ QString CabrilloLog::impl::cabrillo_frequency_string (Radio::Frequency frequency else if ("2m" == band) result = "144"; else if ("4m" == band) result = "70"; else if ("6m" == band) result = "50"; - else result = QString::number (frequency); + else result = QString::number (frequency / 1000ull); return result; } -CabrilloLog::CabrilloLog (Configuration const * configuration) - : m_ {configuration} +#include "moc_CabrilloLog.cpp" + +CabrilloLog::CabrilloLog (Configuration const * configuration, QObject * parent) + : QObject {parent} + , m_ {this, configuration} { Q_ASSERT (configuration); } @@ -141,11 +211,12 @@ namespace } } -bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString const& call +bool CabrilloLog::add_QSO (Frequency frequency, QString const& mode, QDateTime const& when, QString const& call , QString const& exchange_sent, QString const& exchange_received) { auto record = m_->record (); - record.setValue ("frequency", frequency / 1000ull); // kHz + record.setValue ("frequency", frequency); + record.setValue ("mode", mode); if (!when.isNull ()) { record.setValue ("when", when.toMSecsSinceEpoch () / 1000ull); @@ -157,15 +228,16 @@ bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString c set_value_maybe_null (record, "call", call); set_value_maybe_null (record, "exchange_sent", exchange_sent); set_value_maybe_null (record, "exchange_rcvd", exchange_received); - set_value_maybe_null (record, "band", m_->configuration_->bands ()->find (frequency)); if (m_->isDirty ()) { m_->revert (); // discard any uncommitted changes } m_->setEditStrategy (QSqlTableModel::OnManualSubmit); ConditionalTransaction transaction {*m_}; + m_->adding_row_ = true; auto ok = m_->insertRecord (-1, record); transaction.submit (); + m_->adding_row_ = false; m_->setEditStrategy (QSqlTableModel::OnFieldChange); return ok; } @@ -173,10 +245,18 @@ bool CabrilloLog::add_QSO (Frequency frequency, QDateTime const& when, QString c bool CabrilloLog::dupe (Frequency frequency, QString const& call) const { m_->dupe_query_.bindValue (":call", call); - m_->dupe_query_.bindValue (":band", m_->configuration_->bands ()->find (frequency)); SQL_error_check (m_->dupe_query_, static_cast (&QSqlQuery::exec)); - m_->dupe_query_.next (); - return m_->dupe_query_.value (0).toInt (); + auto record = m_->dupe_query_.record (); + auto frequency_index = record.indexOf ("frequency"); + while (m_->dupe_query_.next ()) + { + if (m_->configuration_->bands ()->find (m_->dupe_query_.value (frequency_index).toULongLong ()) + == m_->configuration_->bands ()->find (frequency)) + { + return true; + } + } + return false; } void CabrilloLog::reset () @@ -191,6 +271,7 @@ void CabrilloLog::reset () transaction.submit (); m_->select (); // to refresh views m_->setEditStrategy (QSqlTableModel::OnFieldChange); + Q_EMIT data_changed (); } } @@ -199,6 +280,7 @@ void CabrilloLog::export_qsos (QTextStream& stream) const SQL_error_check (m_->export_query_, static_cast (&QSqlQuery::exec)); auto record = m_->export_query_.record (); auto frequency_index = record.indexOf ("frequency"); + // auto mode_index = record.indexOf ("mode"); auto when_index = record.indexOf ("when"); auto call_index = record.indexOf ("call"); auto sent_index = record.indexOf ("exchange_sent"); @@ -215,3 +297,17 @@ void CabrilloLog::export_qsos (QTextStream& stream) const .arg (m_->export_query_.value (rcvd_index).toString (), -13); } } + +auto CabrilloLog::unique_DXCC_entities (AD1CCty const * countries) const -> worked_set +{ + QSqlQuery q {"SELECT DISTINCT BAND, CALL FROM cabrillo_log_v2"}; + auto band_index = q.record ().indexOf ("band"); + auto call_index = q.record ().indexOf ("call"); + worked_set entities; + while (q.next ()) + { + entities << worked_item {q.value (band_index).toString () + , countries->lookup (q.value (call_index).toString ()).primary_prefix}; + } + return entities; +} diff --git a/models/CabrilloLog.hpp b/models/CabrilloLog.hpp index 43b9e8f94..97d8f0d88 100644 --- a/models/CabrilloLog.hpp +++ b/models/CabrilloLog.hpp @@ -1,33 +1,43 @@ #ifndef CABRILLO_LOG_HPP_ #define CABRILLO_LOG_HPP_ -#include +#include +#include +#include +#include #include "Radio.hpp" #include "pimpl_h.hpp" class Configuration; class QDateTime; -class QString; class QSqlTableModel; class QTextStream; +class AD1CCty; class CabrilloLog final - : private boost::noncopyable + : public QObject { + Q_OBJECT + public: using Frequency = Radio::Frequency; + using worked_item = QPair; + using worked_set = QSet; - explicit CabrilloLog (Configuration const *); + explicit CabrilloLog (Configuration const *, QObject * parent = nullptr); ~CabrilloLog (); // returns false if insert fails - bool add_QSO (Frequency, QDateTime const&, QString const& call + bool add_QSO (Frequency, QString const& mode, QDateTime const&, QString const& call , QString const& report_sent, QString const& report_received); bool dupe (Frequency, QString const& call) const; QSqlTableModel * model (); void reset (); void export_qsos (QTextStream&) const; + worked_set unique_DXCC_entities (AD1CCty const *) const; + + Q_SIGNAL void data_changed () const; private: class impl; diff --git a/models/FoxLog.cpp b/models/FoxLog.cpp index 773a5308f..954090bd6 100644 --- a/models/FoxLog.cpp +++ b/models/FoxLog.cpp @@ -18,14 +18,35 @@ class FoxLog::impl final : public QSqlTableModel { + Q_OBJECT + public: impl (Configuration const * configuration); + QVariant data (QModelIndex const& index, int role) const + { + auto value = QSqlTableModel::data (index, role); + if (index.column () == fieldIndex ("when") + && (Qt::DisplayRole == role || Qt::EditRole == role)) + { + auto t = QDateTime::fromMSecsSinceEpoch (value.toULongLong () * 1000ull, Qt::UTC); + if (Qt::DisplayRole == role) + { + QLocale locale; + return locale.toString (t, locale.dateFormat (QLocale::ShortFormat) + " hh:mm:ss"); + } + value = t; + } + return value; + } + Configuration const * configuration_; QSqlQuery mutable dupe_query_; QSqlQuery mutable export_query_; }; +#include "FoxLog.moc" + FoxLog::impl::impl (Configuration const * configuration) : configuration_ {configuration} { diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp index e57977d1d..c0170a499 100644 --- a/models/FrequencyList.cpp +++ b/models/FrequencyList.cpp @@ -57,49 +57,206 @@ namespace {1838000, Modes::JT65, IARURegions::ALL}, // squeezed allocations {1839000, Modes::JT9, IARURegions::ALL}, {1840000, Modes::FT8, IARURegions::ALL}, - + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 3570 - 3580 DM NB(<200Hz) + // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS + // + // 3577.75 OLIVIA, Contestia, etc. + // 3580 PSK31 + // 3583.25 OLIVIA, Contestia, etc. + // + // R2: 3570 - 3580 DM NB(<200Hz) + // 3580 - 3600 DM NB(<500Hz) with 3590 - 3600 ACDS + // + // 3577.75 OLIVIA, Contestia, etc. + // 3580 PSK31 + // 3583.25 OLIVIA, Contestia, etc. + // 3590 RTTY DX + // 3596 W1AW DM QST + // + // R3: 3535 - 3580 DM NB(<2000Hz) + // + // 3520 - 3575 DM NB(<2000Hz) JA 3535 - 3575 shared with all modes + // + // 3522 OLIVIA, Contestia, etc. + // 3535 JA LSB EMCOMM + // 3580 PSK31 + // 3600 LSB EMCOMM + // {3570000, Modes::JT65, IARURegions::ALL}, // JA compatible {3572000, Modes::JT9, IARURegions::ALL}, - {3573000, Modes::FT8, IARURegions::ALL}, // above as below JT65 - // is out of DM allocation - {3568600, Modes::WSPR, IARURegions::ALL}, // needs guard marker - // and lock out - + {3573000, Modes::FT8, IARURegions::ALL}, // above as below JT65 is out of DM allocation + {3568600, Modes::WSPR, IARURegions::ALL}, // needs guard marker and lock out + {3575000, Modes::FT4, IARURegions::ALL}, // provisional + {3568000, Modes::FT4, IARURegions::R3}, // provisional + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS + // 7050 - 7060 DM WB(<2700Hz) with 7050 - 7053 ACDS + // + // 7040 PSK31 + // 7043.25 OLIVIA, Contestia, etc. (main QRQ) + // 7070 PSK31 + // 7073.25 OLIVIA, Contestia, etc. (main QRQ) + // 7090 LSB QRP CoA + // + // R2: 7040 - 7050 DM NB(<500Hz) with 7047 - 7050 ACDS + // 7050 - 7053 DM WB(<2700Hz) ACDS shared with all modes + // + // 7040 RTTY DX + // 7043.25 OLIVIA, Contestia, etc. (main QRQ) + // 7070 PSK31 (also LSB EMCOMM) + // 7073.25 OLIVIA, Contestia, etc. (main QRQ) + // 7080 - 7125 RTTY/Data + // 7090 LSB QRP CoA + // + // R3: 7030 - 7060 DM NB(<2000Hz) with 7040 - 7060 NB DX all shared with phone + // + // 7030 - 7100 DM WB(<3000Hz) JA 7045 - 7100 shared with all modes + // + // 7026.25 OLIVIA, Contestia, etc. (main QRQ) + // 7035 PSK31 + // 7050 JA LSB EMCOMM + // 7090 LSB QRP CoA + // 7110 LSB EMCOMM + // {7038600, Modes::WSPR, IARURegions::ALL}, {7074000, Modes::FT8, IARURegions::ALL}, {7076000, Modes::JT65, IARURegions::ALL}, {7078000, Modes::JT9, IARURegions::ALL}, + {7047500, Modes::FT4, IARURegions::ALL}, // provisional - moved + // up 500Hz to clear + // W1AW code practice QRG + // Band plans (all USB dial unless stated otherwise) + // + // R1: 10130 - 10150 DM NB(<500Hz) with 10120 - 10140 shared with phone in southern Africa + // + // 10139.25 OLIVIA, Contestia, etc. + // 10142 PSK31 + // 10142.25 OLIVIA, Contestia, etc. + // 10143.25 OLIVIA, Contestia, etc. (main QRQ) + // + // R2: 10130 - 10140 DM NB(<500Hz) shared with ACDS + // 10140 - 10150 DM WB(<2700Hz) + // + // 10130 - 10140 RTTY + // 10139.25 OLIVIA, Contestia, etc. + // 10140 - 10150 Packet + // 10142 PSK31 + // 10142.25 OLIVIA, Contestia, etc. + // 10143.25 OLIVIA, Contestia, etc. (main QRQ) + // + // R3: 10130 - 10150 DM NB(<2000Hz) + // + // 10139.25 OLIVIA, Contestia, etc. + // 10142 PSK31 + // 10142.25 OLIVIA, Contestia, etc. + // 10143.25 OLIVIA, Contestia, etc. (main QRQ) + // {10136000, Modes::FT8, IARURegions::ALL}, {10138000, Modes::JT65, IARURegions::ALL}, {10138700, Modes::WSPR, IARURegions::ALL}, {10140000, Modes::JT9, IARURegions::ALL}, - + {10140000, Modes::FT4, IARURegions::ALL}, // provisional + + // Band plans (all USB dial unless stated otherwise) + // + // R1: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS + // 14101 - 14112 DM NB(<2700Hz) ACDS + // + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14100 NCDXF beacons + // 14105.5 OLIVIA 1000 + // 14106.5 OLIVIA 1000 (main QRG) + // + // R2: 14070 - 14099 DM NB(<500Hz) with 14089 - 14099 ACDS + // 14101 - 14112 DM NB(<2700Hz) ACDS + // + // 14070 - 14095 RTTY + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14095 - 14099.5 Packet + // 14100 NCDXF beacons + // 14100.5 - 14112 Packet + // 14105.5 OLIVIA 1000 + // 14106.5 OLIVIA 1000 (main QRG) + // + // R3: 14070 - 14112 DM NB(<2000Hz) with ±500Hz IBP guard band at 14100 + // + // 14070 PSK31 + // 14074.4 OLIVIA, Contestia, etc. + // 14075.4 OLIVIA, Contestia, etc. (main QRG) + // 14078.4 OLIVIA, Contestia, etc. + // 14100 NCDXF beacons + // 14105.5 OLIVIA 1000 + // 14106.5 OLIVIA 1000 (main QRG) + // {14095600, Modes::WSPR, IARURegions::ALL}, {14074000, Modes::FT8, IARURegions::ALL}, {14076000, Modes::JT65, IARURegions::ALL}, {14078000, Modes::JT9, IARURegions::ALL}, + {14080000, Modes::FT4, IARURegions::ALL}, // provisional + // Band plans (all USB dial unless stated otherwise) + // + // R1: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS + // 18111 - 18120 DM NB(<2700Hz) ACDS + // + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 18104.4 OLIVIA, Contestia, etc. + // 18110 NCDXF beacons + // + // R2: 18095 - 18109 DM NB(<500Hz) with 18105 - 18109 ACDS + // 18111 - 18120 DM NB(<2700Hz) ACDS + // + // 18100 - 18105 RTTY + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 18104.4 OLIVIA, Contestia, etc. + // 18105 - 18110 Packet + // 18110 NCDXF beacons + // + // R3: 18095 - 18120 DM NB(<2000Hz) with ±500Hz IBP guard band at 18110 + // + // 18100 PSK31 + // 18103.4 OLIVIA, Contestia, etc. (main QRG) + // 18104.4 OLIVIA, Contestia, etc. + // 18110 NCDXF beacons + // {18100000, Modes::FT8, IARURegions::ALL}, {18102000, Modes::JT65, IARURegions::ALL}, {18104000, Modes::JT9, IARURegions::ALL}, + {18104000, Modes::FT4, IARURegions::ALL}, // provisional {18104600, Modes::WSPR, IARURegions::ALL}, {21074000, Modes::FT8, IARURegions::ALL}, {21076000, Modes::JT65, IARURegions::ALL}, {21078000, Modes::JT9, IARURegions::ALL}, {21094600, Modes::WSPR, IARURegions::ALL}, - + {21140000, Modes::FT4, IARURegions::ALL}, + {24915000, Modes::FT8, IARURegions::ALL}, {24917000, Modes::JT65, IARURegions::ALL}, {24919000, Modes::JT9, IARURegions::ALL}, + {24919000, Modes::FT4, IARURegions::ALL}, // provisional {24924600, Modes::WSPR, IARURegions::ALL}, {28074000, Modes::FT8, IARURegions::ALL}, {28076000, Modes::JT65, IARURegions::ALL}, {28078000, Modes::JT9, IARURegions::ALL}, {28124600, Modes::WSPR, IARURegions::ALL}, - + {28180000, Modes::FT4, IARURegions::ALL}, + {50200000, Modes::Echo, IARURegions::ALL}, {50276000, Modes::JT65, IARURegions::R2}, {50276000, Modes::JT65, IARURegions::R3}, @@ -111,6 +268,7 @@ namespace {50310000, Modes::JT65, IARURegions::ALL}, {50312000, Modes::JT9, IARURegions::ALL}, {50313000, Modes::FT8, IARURegions::ALL}, + {50318000, Modes::FT4, IARURegions::ALL}, // provisional {50323000, Modes::FT8, IARURegions::ALL}, {70100000, Modes::FT8, IARURegions::R1}, @@ -121,6 +279,7 @@ namespace {144120000, Modes::JT65, IARURegions::ALL}, {144120000, Modes::Echo, IARURegions::ALL}, + {144170000, Modes::FT4, IARURegions::ALL}, {144174000, Modes::FT8, IARURegions::ALL}, {144360000, Modes::MSK144, IARURegions::R1}, {144150000, Modes::MSK144, IARURegions::R2}, diff --git a/models/IARURegions.cpp b/models/IARURegions.cpp index 25450ab47..dcdc94d43 100644 --- a/models/IARURegions.cpp +++ b/models/IARURegions.cpp @@ -7,8 +7,6 @@ #include #include -#include "moc_IARURegions.cpp" - namespace { // human readable strings for each Region enumeration value @@ -22,6 +20,8 @@ namespace std::size_t constexpr region_names_size = sizeof (region_names) / sizeof (region_names[0]); } +#include "moc_IARURegions.cpp" + IARURegions::IARURegions (QObject * parent) : QAbstractListModel {parent} { diff --git a/models/IARURegions.hpp b/models/IARURegions.hpp index d849d97b7..498846d34 100644 --- a/models/IARURegions.hpp +++ b/models/IARURegions.hpp @@ -29,6 +29,7 @@ class IARURegions final : public QAbstractListModel { Q_OBJECT + public: // // This enumeration contains the supported regions, to complement diff --git a/models/Modes.cpp b/models/Modes.cpp index 9d21459c7..838585b2a 100644 --- a/models/Modes.cpp +++ b/models/Modes.cpp @@ -23,7 +23,8 @@ namespace "MSK144", "QRA64", "FreqCal", - "FT8" + "FT8", + "FT4" }; std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]); } diff --git a/models/Modes.hpp b/models/Modes.hpp index cdf299749..fea55e4d4 100644 --- a/models/Modes.hpp +++ b/models/Modes.hpp @@ -49,6 +49,7 @@ public: QRA64, FreqCal, FT8, + FT4, MODES_END_SENTINAL_AND_COUNT // this must be last }; Q_ENUM (Mode) diff --git a/models/StationList.cpp b/models/StationList.cpp index eeeb4d607..202cac0e7 100644 --- a/models/StationList.cpp +++ b/models/StationList.cpp @@ -52,6 +52,8 @@ QDataStream& operator >> (QDataStream& is, StationList::Station& station) class StationList::impl final : public QAbstractTableModel { + Q_OBJECT + public: impl (Bands const * bands, Stations stations, QObject * parent) : QAbstractTableModel {parent} @@ -97,6 +99,9 @@ public: Stations stations_; }; +#include "StationList.moc" +#include "moc_StationList.cpp" + StationList::StationList (Bands const * bands, QObject * parent) : StationList {bands, {}, parent} { diff --git a/models/StationList.hpp b/models/StationList.hpp index 25bf428fc..3b0955c18 100644 --- a/models/StationList.hpp +++ b/models/StationList.hpp @@ -40,6 +40,8 @@ class Bands; class StationList final : public QSortFilterProxyModel { + Q_OBJECT + public: using Frequency = Radio::Frequency; using FrequencyDelta = Radio::FrequencyDelta; diff --git a/models/models.pri b/models/models.pri index e0c69e81e..5b3d038bb 100644 --- a/models/models.pri +++ b/models/models.pri @@ -5,7 +5,8 @@ SOURCES += \ models/Modes.cpp \ models/IARURegions.cpp \ models/FoxLog.cpp \ - models/CabrilloLog.cpp + models/CabrilloLog.cpp \ + models/DecodeHighlightingModel.cpp HEADERS += \ models/Bands.hpp \ @@ -15,4 +16,5 @@ HEADERS += \ models/IARURegions.hpp \ models/FoxLog.hpp \ models/CabrilloLog.hpp \ - models/FontOverrideModel.hpp + models/FontOverrideModel.hpp \ + models/DecodeHighlightingModel.hpp diff --git a/qt_db_helpers.hpp b/qt_db_helpers.hpp index 49a082f72..dcf9d0333 100644 --- a/qt_db_helpers.hpp +++ b/qt_db_helpers.hpp @@ -6,6 +6,7 @@ #include #include #include +#include "boost/core/noncopyable.hpp" template void SQL_error_check (T&& object, Func func, Args&&... args) diff --git a/robots/go b/robots/go new file mode 100755 index 000000000..f7bf846fc --- /dev/null +++ b/robots/go @@ -0,0 +1,2 @@ +curl https://pskreporter.info/cgi-bin/robot.pl > robo.dat +robo | sort -nr -k2 -k1 diff --git a/robots/robo.f90 b/robots/robo.f90 new file mode 100644 index 000000000..1f748378c --- /dev/null +++ b/robots/robo.f90 @@ -0,0 +1,48 @@ +program robo + +! Examine spots from PSK Reporter for past week to identify probable robots + +! In a bash shell, from command line: +! $ curl https://pskreporter.info/cgi-bin/robot.pl > robo.dat +! $ robo | sort -nr -k2 + + parameter (NCHARS=20000) + parameter (NMAX=100) + + character*1 c + character*20000 blob + character*12 callsign(0:NMAX) + integer*1 ic1 + + open(10,file='/tmp/robo.dat',status='old',access='stream') + callsign=' ' + + do ichar=1,NCHARS + read(10,end=10) ic1 + ic=ic1 + if(ic.lt.0) ic=ic+256 + c=char(ic) + blob(ichar:ichar)=c + enddo +10 continue + + do icall=1,NMAX + i1=index(blob,'":{"median_minutes":')-1 + do i=i1,i1-10,-1 + if(i1.lt.1) go to 20 + if(blob(i:i).eq.'"') exit + enddo + i0=i+1 + callsign(icall)=blob(i0:i1) + i2=index(blob,',')-1 + read(blob(i1+21:i2),*) median_minutes + i3=index(blob,'median_hours')+14 + i4=index(blob,'}')-1 + read(blob(i3:i4),*) median_hours + write(*,3001) median_minutes,median_hours,trim(callsign(icall)) +3001 format(2i5,2x,a) + blob=blob(i4+3:) + enddo + +20 continue +end program robo diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 78bdcf07e..271d2d3c4 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -1,4 +1,5 @@ set (SAMPLE_FILES + FT4/000000_000002.wav FT8/181201_180245.wav ISCAT/ISCAT-A/VK7MO_110401_235515.wav ISCAT/ISCAT-B/K0AWU_100714_115000.wav diff --git a/samples/FT4/000000_000002.wav b/samples/FT4/000000_000002.wav new file mode 100644 index 000000000..e5cdc8804 Binary files /dev/null and b/samples/FT4/000000_000002.wav differ diff --git a/shortcuts.txt b/shortcuts.txt index e50278d0f..93c75585b 100644 --- a/shortcuts.txt +++ b/shortcuts.txt @@ -8,19 +8,21 @@ F4 Clear DX Call, DX Grid, Tx messages 1-4 (Alt: transmit Tx4) Alt+F4 Exit program F5 Display special mouse commands (Alt: transmit Tx5) - F6 Open next file in directory + F6 Open next file in directory (Alt: toggle "Call 1st") Shift+F6 Decode all remaining files in directrory F7 Display Message Averaging window F11 Move Rx frequency down 1 Hz Ctrl+F11 Move identical Rx and Tx frequencies down 1 Hz - Shift+F11 Move Tx frequency down 60 Hz + Shift+F11 Move Tx frequency down 60 Hz (FT8) or 90 Hz (FT4) Ctrl+Shift+F11 Move dial frequency down 2000 Hz F12 Move Rx frequency up 1 Hz Ctrl+F12 Move identical Rx and Tx frequencies up 1 Hz - Shift+F12 Move Tx frequency up 60 Hz + Shift+F12 Move Tx frequency up 60 Hz (FT8) or 90 Hz (FT4) Ctrl+Shift+F12 Move dial frequency up 2000 Hz Alt+1-6 Set now transmission to this number on Tab 1 Ctl+1-6 Set next transmission to this number on Tab 1 + Alt+B Toggle "Best S+P" status + Alt+C Toggle "Call 1st" checkbox Alt+D Decode again at QSO frequency Shift+D Full decode (both windows) Ctrl+E Turn on TX even/1st @@ -33,6 +35,7 @@ Alt+M Monitor Alt+N Enable Tx Ctrl+O Open a .wav file + Alt+O Change operator Alt+Q Log QSO Alt+S Stop monitoring Alt+T Tune diff --git a/soundout.cpp b/soundout.cpp index a4f8800df..0264ad91e 100644 --- a/soundout.cpp +++ b/soundout.cpp @@ -9,11 +9,14 @@ #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 { @@ -101,7 +104,7 @@ void SoundOutput::restart (QIODevice * source) 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(); - + m_stream->setCategory ("production"); m_stream->start (source); } diff --git a/translations/wsjtx_en_GB.ts b/translations/wsjtx_en_GB.ts new file mode 100644 index 000000000..2e0570962 --- /dev/null +++ b/translations/wsjtx_en_GB.ts @@ -0,0 +1,6007 @@ + + + + + AbstractLogWindow + + + &Delete ... + + + + + AbstractLogWindow::impl + + + Confirm Delete + + + + + Are you sure you want to delete the %n selected QSO(s) from the log + + + + + + + + Astro + + + + Doppler tracking + + + + + <html><head/><body><p>One station does all Doppler shift correction, their QSO partner receives and transmits on the sked frequency.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p></body></html> + + + + + Full Doppler to DX Grid + + + + + <html><head/><body><p>Transmit takes place on sked frequency and receive frequency is corrected for own echoes. </p><p>This mode can be used for calling CQ, or when using Echo mode.</p></body></html> + + + + + Own Echo + + + + + <html><head/><body><p>Both stations correct for Doppler shift such that they would be heard on the moon at the sked frequency.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p><p>Use this option also for Echo mode.</p></body></html> + + + + + Constant frequency on Moon + + + + + <html><head/><body><p>DX station announces their TX Freq, which is entered as the Sked Freq. Correction applied to RX and TX so you appear on the DX's station's own echo Freq.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p></body></html> + + + + + On DX Echo + + + + + <html><head/><body><p>Tune radio manually and select this mode to put your echo on the same frequency.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p></body></html> + + + + + Call DX + + + + + <html><head/><body><p>No Doppler shift correction is applied. This may be used when the QSO partner does full Doppler correction to your grid square.</p></body></html> + + + + + None + + + + + Sked frequency + + + + + + 0 + + + + + Rx: + + + + + Tx: + + + + + <html><head/><body><p>Press and hold the CTRL key to adjust the sked frequency manually with the rig's VFO dial or enter frequency directly into the band entry field on the main window.</p></body></html> + + + + + Astro Data + + + + + Astronomical Data + + + + + Doppler Tracking Error + + + + + Split operating is required for Doppler tracking + + + + + Go to "Menu->File->Settings->Radio" to enable split operation + + + + + Bands + + + Band name + + + + + Lower frequency limit + + + + + Upper frequency limit + + + + + Band + + + + + Lower Limit + + + + + Upper Limit + + + + + CAboutDlg + + + About WSJT-X + + + + + OK + + + + + CPlotter + + + &Set Rx && Tx Offset + + + + + CabrilloLog + + + Freq(MHz) + + + + + Mode + + + + + Date & Time(UTC) + + + + + Call + + + + + Sent + + + + + Rcvd + + + + + Band + + + + + CabrilloLogWindow + + + Contest Log + + + + + <html><head/><body><p>Right-click here for available actions.</p></body></html> + + + + + Right-click here for available actions. + + + + + CallsignDialog + + + Callsign + + + + + ColorHighlighting + + + + + + + + + + + + + + + + + + K1ABC + + + + + CQ in message + + + + + My Call in message + + + + + Transmitted message + + + + + New DXCC + + + + + New Grid + + + + + New DXCC on Band + + + + + New Call + + + + + New Grid on Band + + + + + New Call on Band + + + + + Uploads to LotW + + + + + New Continent + + + + + New Continent on Band + + + + + New CQ Zone + + + + + New CQ Zone on Band + + + + + New ITU Zone + + + + + New ITU Zone on Band + + + + + Configuration::impl + + + + + &Delete + + + + + + &Insert ... + + + + + Failed to create save directory + + + + + path: "%1% + + + + + Failed to create samples directory + + + + + path: "%1" + + + + + &Load ... + + + + + &Save as ... + + + + + &Merge ... + + + + + &Reset + + + + + Serial Port: + + + + + Serial port used for CAT control + + + + + Network Server: + + + + + Optional hostname and port of network service. +Leave blank for a sensible default on this machine. +Formats: + hostname:port + IPv4-address:port + [IPv6-address]:port + + + + + USB Device: + + + + + Optional device identification. +Leave blank for a sensible default for the rig. +Format: + [VID[:PID[:VENDOR[:PRODUCT]]]] + + + + + Invalid audio input device + + + + + Invalid audio out device + + + + + Invalid PTT method + + + + + Invalid PTT port + + + + + + Invalid Contest Exchange + + + + + You must input a valid ARRL Field Day exchange + + + + + You must input a valid ARRL RTTY Roundup exchange + + + + + Reset Decode Highlighting + + + + + Reset all decode highlighting and priorities to default values + + + + + WSJT-X Decoded Text Font Chooser + + + + + Load Working Frequencies + + + + + + + Frequency files (*.qrg);;All files (*.*) + + + + + Replace Working Frequencies + + + + + Are you sure you want to discard your current working frequencies and replace them with the loaded ones? + + + + + Merge Working Frequencies + + + + + + + Not a valid frequencies file + + + + + Incorrect file magic + + + + + Version is too new + + + + + Contents corrupt + + + + + Save Working Frequencies + + + + + Only Save Selected Working Frequencies + + + + + Are you sure you want to save only the working frequencies that are currently selected? Click No to save all. + + + + + Reset Working Frequencies + + + + + Are you sure you want to discard your current working frequencies and replace them with default ones? + + + + + Save Directory + + + + + AzEl Directory + + + + + Rig control error + + + + + Failed to open connection to rig + + + + + Rig failure + + + + + DXLabSuiteCommanderTransceiver + + + Failed to connect to DX Lab Suite Commander + + + + + + DX Lab Suite Commander didn't respond correctly reading frequency: + + + + + DX Lab Suite Commander sent an unrecognised TX state: + + + + + DX Lab Suite Commander didn't respond correctly polling TX status: + + + + + DX Lab Suite Commander rig did not respond to PTT: + + + + + DX Lab Suite Commander didn't respond correctly polling frequency: + + + + + DX Lab Suite Commander didn't respond correctly polling TX frequency: + + + + + DX Lab Suite Commander sent an unrecognised split state: + + + + + DX Lab Suite Commander didn't respond correctly polling split status: + + + + + DX Lab Suite Commander sent an unrecognised mode: " + + + + + DX Lab Suite Commander didn't respond correctly polling mode: + + + + + DX Lab Suite Commander send command failed + + + + + + DX Lab Suite Commander failed to send command "%1": %2 + + + + + + DX Lab Suite Commander send command "%1" read reply failed: %2 + + + + + + DX Lab Suite Commander retries exhausted sending command "%1" + + + + + DX Lab Suite Commander sent an unrecognized frequency + + + + + DecodeHighlightingListView + + + &Foreground color ... + + + + + Choose %1 Foreground Color + + + + + &Unset foreground color + + + + + &Background color ... + + + + + Choose %1 Background Color + + + + + U&nset background color + + + + + &Reset this item to defaults + + + + + DecodeHighlightingModel + + + Highlight Type + + + + + Designer + + + &Delete + + + + + &Insert ... + + + + + Insert &after ... + + + + + Import Palette + + + + + + Palettes (*.pal) + + + + + Export Palette + + + + + Dialog + + + Gray time: + + + + + Directory + + + + URL Error + + + + + + Invalid URL: +"%1" + + + + + + + + + + + JSON Error + + + + + Contents file syntax error %1 at character offset %2 + + + + + Contents file top level must be a JSON array + + + + + File System Error + + + + + Failed to open "%1" +Error: %2 - %3 + + + + + Contents entries must be a JSON array + + + + + Contents entries must have a valid type + + + + + Contents entries must have a valid name + + + + + Contents entries must be JSON objects + + + + + Contents directories must be relative and within "%1" + + + + + Network Error + + + + + Authentication required + + + + + DisplayText + + + &Erase + + + + + EchoGraph + + + + Echo Graph + + + + + <html><head/><body><p>Compression factor for frequency scale</p></body></html> + + + + + Bins/Pixel + + + + + Gain + + + + + <html><head/><body><p>Echo spectrum gain</p></body></html> + + + + + Zero + + + + + <html><head/><body><p>Echo spectrum zero</p></body></html> + + + + + <html><head/><body><p>Smoothing of echo spectrum</p></body></html> + + + + + Smooth + + + + + <html><head/><body><p>Number of echo transmissions averaged</p></body></html> + + + + + N: 0 + + + + + <html><head/><body><p>Click to cycle through a sequence of colors and line widths.</p></body></html> + + + + + Colors + Colours + + + + EmulateSplitTransceiver + + + Emulated split mode requires rig to be in simplex mode + + + + + EqualizationToolsDialog::impl + + + Phase + + + + + + Freq (Hz) + + + + + Phase (Π) + + + + + Delay (ms) + + + + + Measured + + + + + Proposed + + + + + Current + + + + + Group Delay + + + + + Amplitude + + + + + Relative Power (dB) + + + + + Reference + + + + + Phase ... + + + + + Refresh + + + + + Discard Measured + + + + + ExistingNameDialog + + + Configuration to Clone From + + + + + &Source Configuration Name: + + + + + ExportCabrillo + + + Dialog + + + + + Location: + + + + + SNJ + + + + + Contest: + + + + + ARRL-RTTY + + + + + Callsign: + + + + + Category-Operator: + + + + + SINGLE-OP + + + + + Category-Transmitter: + + + + + ONE + + + + + Category-Power: + + + + + LOW + + + + + Category-Assisted: + + + + + NON-ASSISTED + + + + + Category-Band: + + + + + ALL + + + + + Claimed-Score: + + + + + Operators: + + + + + Club: + + + + + Name: + + + + + + Address: + + + + + Save Log File + + + + + Cabrillo Log (*.cbr) + + + + + Cannot open "%1" for writing: %2 + + + + + Export Cabrillo File Error + + + + + FastGraph + + + + Fast Graph + + + + + Waterfall gain + + + + + Waterfall zero + + + + + Spectrum zero + + + + + <html><head/><body><p>Set reasonable levels for gain and zero sliders.</p></body></html> + + + + + Auto Level + + + + + FoxLog::impl + + + Date & Time(UTC) + + + + + Call + + + + + Grid + + + + + Sent + + + + + Rcvd + + + + + Band + + + + + FoxLogWindow + + + Fox Log + + + + + <html><head/><body><p>Right-click here for available actions.</p></body></html> + + + + + Callers: + + + + + + + N + + + + + In progress: + + + + + Rate: + + + + + &Export ADIF ... + + + + + Export ADIF Log File + + + + + ADIF Log (*.adi) + + + + + Export ADIF File Error + + + + + Cannot open "%1" for writing: %2 + + + + + &Reset ... + + + + + Confirm Reset + + + + + Are you sure you want to erase file FoxQSO.txt and start a new Fox log? + + + + + FrequencyDialog + + + Add Frequency + + + + + IARU &Region: + + + + + &Mode: + + + + + &Frequency (MHz): + + + + + FrequencyList_v2 + + + + IARU Region + + + + + + Mode + + + + + + Frequency + + + + + + Frequency (MHz) + + + + + HRDTransceiver + + + + Failed to connect to Ham Radio Deluxe + + + + + + Failed to open file "%1": %2. + + + + + + Ham Radio Deluxe: no rig found + + + + + Ham Radio Deluxe: rig doesn't support mode + + + + + Ham Radio Deluxe: sent an unrecognised mode + + + + + Ham Radio Deluxe: item not found in %1 dropdown list + + + + + Ham Radio Deluxe: button not available + + + + + Ham Radio Deluxe didn't respond as expected + + + + + Ham Radio Deluxe: rig has disappeared or changed + + + + + Ham Radio Deluxe send command "%1" failed %2 + + + + + + + Ham Radio Deluxe: failed to write command "%1" + + + + + Ham Radio Deluxe sent an invalid reply to our command "%1" + + + + + Ham Radio Deluxe failed to reply to command "%1" %2 + + + + + + Ham Radio Deluxe retries exhausted sending command "%1" + + + + + Ham Radio Deluxe didn't respond to command "%1" as expected + + + + + HamlibTransceiver + + + + Hamlib initialisation error + + + + + Hamlib settings file error: %1 at character offset %2 + + + + + Hamlib settings file error: top level must be a JSON object + + + + + Hamlib settings file error: config must be a JSON object + + + + + Unsupported CAT type + + + + + Hamlib error: %1 while %2 + + + + + opening connection to rig + + + + + getting current frequency + + + + + getting current mode + + + + + + exchanging VFOs + + + + + + getting other VFO frequency + + + + + getting other VFO mode + + + + + setting current VFO + + + + + getting frequency + + + + + getting mode + + + + + + getting current VFO + + + + + + + + getting current VFO frequency + + + + + + + + + + setting frequency + + + + + + + + getting current VFO mode + + + + + + + + + setting current VFO mode + + + + + + setting/unsetting split mode + + + + + + setting split mode + + + + + setting split TX frequency and mode + + + + + setting split TX frequency + + + + + getting split TX VFO mode + + + + + setting split TX VFO mode + + + + + getting PTT state + + + + + setting PTT on + + + + + setting PTT off + + + + + setting a configuration item + + + + + getting a configuration item + + + + + HelpTextWindow + + + Help file error + + + + + Cannot open "%1" for reading + + + + + Error: %1 + + + + + IARURegions + + + + IARU Region + + + + + LogQSO + + + Click OK to confirm the following QSO: + + + + + Call + + + + + Start + + + + + + dd/MM/yyyy HH:mm:ss + + + + + End + + + + + Mode + + + + + Band + + + + + Rpt Sent + + + + + Rpt Rcvd + + + + + Grid + + + + + Name + + + + + Tx power + + + + + + Retain + + + + + Comments + + + + + Operator + + + + + Exch sent + + + + + Rcvd + + + + + + Invalid QSO Data + + + + + Check exchange sent and received + + + + + Check all fields + + + + + Log file error + + + + + Cannot open "%1" for append + + + + + Error: %1 + + + + + LotWUsers::impl + + + Network Error - SSL/TLS support not installed, cannot fetch: +'%1' + + + + + Network Error - Too many redirects: +'%1' + + + + + Network Error: +%1 + + + + + File System Error - Cannot commit changes to: +"%1" + + + + + File System Error - Cannot open file: +"%1" +Error(%2): %3 + + + + + File System Error - Cannot write to file: +"%1" +Error(%2): %3 + + + + + MainWindow + + + WSJT-X by K1JT + + + + + Band Activity + + + + + + UTC dB DT Freq Dr + + + + + Rx Frequency + + + + + CQ only + + + + + Enter this QSO in log + + + + + Log &QSO + + + + + Stop monitoring + + + + + &Stop + + + + + Toggle monitoring On/Off + + + + + &Monitor + + + + + <html><head/><body><p>Erase right window. Double-click to erase both windows.</p></body></html> + + + + + Erase right window. Double-click to erase both windows. + + + + + &Erase + + + + + <html><head/><body><p>Clear the accumulating message average.</p></body></html> + + + + + Clear the accumulating message average. + + + + + Clear Avg + + + + + <html><head/><body><p>Decode most recent Rx period at QSO Frequency</p></body></html> + + + + + Decode most recent Rx period at QSO Frequency + + + + + &Decode + + + + + <html><head/><body><p>Toggle Auto-Tx On/Off</p></body></html> + + + + + Toggle Auto-Tx On/Off + + + + + E&nable Tx + + + + + Stop transmitting immediately + + + + + &Halt Tx + + + + + <html><head/><body><p>Toggle a pure Tx tone On/Off</p></body></html> + + + + + Toggle a pure Tx tone On/Off + + + + + &Tune + + + + + Menus + + + + + USB dial frequency + + + + + 14.078 000 + + + + + <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> + + + + + Rx Signal + + + + + 30dB recommended when only noise present +Green when good +Red when clipping may occur +Yellow when too low + + + + + DX Call + + + + + DX Grid + + + + + Callsign of station to be worked + + + + + Search for callsign in database + + + + + &Lookup + + + + + Locator of station to be worked + + + + + Az: 251 16553 km + + + + + Add callsign and locator to database + + + + + Add + + + + + Pwr + + + + + <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> + + + + + If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode. + + + + + ? + + + + + Adjust Tx audio level + + + + + <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html> + + + + + Frequncy entry + + + + + Select operating band or enter frequency in MHz or enter kHz increment followed by k. + + + + + <html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html> + + + + + <html><head/><body><p>Check to keep Tx frequency fixed when double-clicking on decoded text.</p></body></html> + + + + + Check to keep Tx frequency fixed when double-clicking on decoded text. + + + + + Hold Tx Freq + + + + + Audio Rx frequency + + + + + + + Hz + + + + + Rx + + + + + Set Tx frequency to Rx Frequency + + + + + â–² + + + + + Frequency tolerance (Hz) + + + + + F Tol + + + + + Set Rx frequency to Tx Frequency + + + + + â–¼ + + + + + <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> + + + + + Synchronizing threshold. Lower numbers accept weaker sync signals. + + + + + Sync + + + + + <html><head/><body><p>Check to use short-format messages.</p></body></html> + + + + + Check to use short-format messages. + + + + + Sh + + + + + <html><head/><body><p>Check to enable JT9 fast modes</p></body></html> + + + + + Check to enable JT9 fast modes + + + + + + Fast + + + + + <html><head/><body><p>Check to enable automatic sequencing of Tx messages based on received messages.</p></body></html> + + + + + Check to enable automatic sequencing of Tx messages based on received messages. + + + + + Auto Seq + + + + + <html><head/><body><p>Check to call the first decoded responder to my CQ.</p></body></html> + + + + + Check to call the first decoded responder to my CQ. + + + + + Call 1st + + + + + Check to generate "@1250 (SEND MSGS)" in Tx6. + + + + + Tx6 + + + + + <html><head/><body><p>Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences.</p></body></html> + + + + + Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences. + + + + + Tx even/1st + + + + + <html><head/><body><p>Frequency to call CQ on in kHz above the current MHz</p></body></html> + + + + + Frequency to call CQ on in kHz above the current MHz + + + + + Tx CQ + + + + + <html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to nonstandard callsign holders.</p></body></html> + + + + + Check this to call CQ on the "Tx CQ" frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on. +Not available to nonstandard callsign holders. + + + + + Rx All Freqs + + + + + <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> + + + + + Submode determines tone spacing; A is narrowest. + + + + + Submode + + + + + Fox + + + + + <html><head/><body><p>Check to monitor Sh messages.</p></body></html> + + + + + Check to monitor Sh messages. + + + + + SWL + + + + + Best S+P + + + + + <html><head/><body><p>Check this to start recording calibration data.<br/>While measuring calibration correction is disabled.<br/>When not checked you can view the calibration results.</p></body></html> + + + + + Check this to start recording calibration data. +While measuring calibration correction is disabled. +When not checked you can view the calibration results. + + + + + Measure + + + + + <html><head/><body><p>Signal report: Signal-to-noise ratio in 2500 Hz reference bandwidth (dB).</p></body></html> + + + + + Signal report: Signal-to-noise ratio in 2500 Hz reference bandwidth (dB). + + + + + Report + + + + + <html><head/><body><p>Tx/Rx or Frequency calibration sequence length</p></body></html> + + + + + Tx/Rx or Frequency calibration sequence length + + + + + s + + + + + T/R + + + + + Toggle Tx mode + + + + + Tx JT9 @ + + + + + Audio Tx frequency + + + + + + Tx + + + + + Tx# + + + + + <html><head/><body><p>Double-click on another caller to queue that call for your next QSO.</p></body></html> + + + + + Double-click on another caller to queue that call for your next QSO. + + + + + Next Call + + + + + 1 + + + + + + + Send this message in next Tx interval + + + + + Ctrl+2 + + + + + <html><head/><body><p>Send this message in next Tx interval</p><p>Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders)</p></body></html> + + + + + Send this message in next Tx interval +Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders) + + + + + Ctrl+1 + + + + + + + + Switch to this Tx message NOW + + + + + Tx &2 + + + + + Alt+2 + + + + + <html><head/><body><p>Switch to this Tx message NOW</p><p>Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders)</p></body></html> + + + + + Switch to this Tx message NOW +Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders) + + + + + Tx &1 + + + + + Alt+1 + + + + + Ctrl+6 + + + + + <html><head/><body><p>Send this message in next Tx interval</p><p>Double-click to reset to the standard 73 message</p></body></html> + + + + + Send this message in next Tx interval +Double-click to reset to the standard 73 message + + + + + Ctrl+5 + + + + + Ctrl+3 + + + + + Tx &3 + + + + + Alt+3 + + + + + <html><head/><body><p>Send this message in next Tx interval</p><p>Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type 2 compound call holders)</p><p>RR73 messages should only be used when you are reasonably confident that no message repetitions will be required</p></body></html> + + + + + Send this message in next Tx interval +Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type 2 compound call holders) +RR73 messages should only be used when you are reasonably confident that no message repetitions will be required + + + + + Ctrl+4 + + + + + <html><head/><body><p>Switch to this Tx message NOW</p><p>Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type2 compound call holders)</p><p>RR73 messages should only be used when you are reasonably confident that no message repetitions will be required</p></body></html> + + + + + Switch to this Tx message NOW +Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type2 compound call holders) +RR73 messages should only be used when you are reasonably confident that no message repetitions will be required + + + + + Tx &4 + + + + + Alt+4 + + + + + <html><head/><body><p>Switch to this Tx message NOW</p><p>Double-click to reset to the standard 73 message</p></body></html> + + + + + Switch to this Tx message NOW +Double-click to reset to the standard 73 message + + + + + Tx &5 + + + + + Alt+5 + + + + + Now + + + + + Generate standard messages for minimal QSO + + + + + Generate Std Msgs + + + + + Tx &6 + + + + + Alt+6 + + + + + + Enter a free text message (maximum 13 characters) +or select a predefined macro from the dropdown list. +Press ENTER to add the current text to the predefined +list. The list can be maintained in Settings (F2). + + + + + Queue up the next Tx message + + + + + Next + + + + + 2 + + + + + Calling CQ + + + + + Generate a CQ message + + + + + + + CQ + + + + + Generate message with RRR + + + + + RRR + + + + + Generate message with report + + + + + dB + + + + + Answering CQ + + + + + Generate message for replying to a CQ + + + + + + Grid + + + + + Generate message with R+report + + + + + R+dB + + + + + Generate message with 73 + + + + + 73 + + + + + Send this standard (generated) message + + + + + Gen msg + + + + + Send this free-text message (max 13 characters) + + + + + Free msg + + + + + 3 + + + + + Max dB + + + + + CQ AF + + + + + CQ AN + + + + + CQ AS + + + + + CQ EU + + + + + CQ NA + + + + + CQ OC + + + + + CQ SA + + + + + CQ 0 + + + + + CQ 1 + + + + + CQ 2 + + + + + CQ 3 + + + + + CQ 4 + + + + + CQ 5 + + + + + CQ 6 + + + + + CQ 7 + + + + + CQ 8 + + + + + CQ 9 + + + + + Reset + + + + + N List + + + + + N Slots + + + + + + Random + + + + + Call + + + + + S/N (dB) + + + + + Distance + + + + + More CQs + + + + + Percentage of 2-minute sequences devoted to transmitting. + + + + + % + + + + + Tx Pct + + + + + Band Hopping + + + + + Choose bands and times of day for band-hopping. + + + + + Schedule ... + + + + + Upload decoded messages to WSPRnet.org. + + + + + Upload spots + + + + + <html><head/><body><p>6 digit locators cause 2 different mesages to be sent, the second contains the full locator but only a hashed callsign, other stations must have decoded the first once before they can decode your call in the second. Check this option to only send 4 digit locators if it will avoid the two message protocol.</p></body></html> + + + + + 6 digit locators cause 2 different mesages to be sent, the second contains the full locator but only a hashed callsign, other stations must have decoded the first once before they can decode your call in the second. Check this option to only send 4 digit locators if it will avoid the two message protocol. + + + + + Prefer type 1 messages + + + + + No own call decodes + + + + + Transmit during the next 2-minute sequence. + + + + + Tx Next + + + + + Set Tx power in dBm (dB above 1 mW) as part of your WSPR message. + + + + + File + + + + + View + + + + + Decode + + + + + Save + + + + + Help + + + + + Mode + + + + + Configurations + + + + + Tools + + + + + Exit + + + + + Configuration + + + + + F2 + + + + + About WSJT-X + + + + + Waterfall + + + + + Open + + + + + Ctrl+O + + + + + Open next in directory + + + + + Decode remaining files in directory + + + + + Shift+F6 + + + + + Delete all *.wav && *.c2 files in SaveDir + + + + + None + + + + + Save all + + + + + Online User Guide + + + + + Keyboard shortcuts + + + + + Special mouse commands + + + + + JT9 + + + + + Save decoded + + + + + Normal + + + + + Deep + + + + + Monitor OFF at startup + + + + + Erase ALL.TXT + + + + + Erase wsjtx_log.adi + + + + + Convert mode to RTTY for logging + + + + + Log dB reports to Comments + + + + + Prompt me to log QSO + + + + + Blank line between decoding periods + + + + + Clear DX Call and Grid after logging + + + + + Display distance in miles + + + + + Double-click on call sets Tx Enable + + + + + + F7 + + + + + Tx disabled after sending 73 + + + + + Runaway Tx watchdog + + + + + Allow multiple instances + + + + + Tx freq locked to Rx freq + + + + + JT65 + + + + + JT9+JT65 + + + + + Tx messages to Rx Frequency window + + + + + Gray1 + + + + + Show DXCC entity and worked B4 status + + + + + Astronomical data + + + + + List of Type 1 prefixes and suffixes + + + + + Settings... + + + + + Local User Guide + + + + + Open log directory + + + + + JT4 + + + + + Message averaging + + + + + Enable averaging + + + + + Enable deep search + + + + + WSPR + + + + + Echo Graph + + + + + F8 + + + + + Echo + + + + + EME Echo mode + + + + + ISCAT + + + + + Fast Graph + + + + + F9 + + + + + &Download Samples ... + + + + + <html><head/><body><p>Download sample audio files demonstrating the various modes.</p></body></html> + + + + + MSK144 + + + + + QRA64 + + + + + Release Notes + + + + + Enable AP for DX Call + + + + + FreqCal + + + + + Measure reference spectrum + + + + + Measure phase response + + + + + Erase reference spectrum + + + + + Execute frequency calibration cycle + + + + + Equalization tools ... + + + + + WSPR-LF + + + + + Experimental LF/MF mode + + + + + FT8 + + + + + + Enable AP + + + + + Solve for calibration parameters + + + + + Copyright notice + + + + + Shift+F1 + + + + + Fox log + + + + + FT8 DXpedition Mode User Guide + + + + + Reset Cabrillo log ... + + + + + Color highlighting scheme + + + + + Contest Log + + + + + Export Cabrillo log ... + + + + + Quick-Start Guide to WSJT-X 2.0 + + + + + Contest log + + + + + Erase WSPR hashtable + + + + + FT4 + + + + + Rig Control Error + + + + + Do you want to reconfigure the radio interface? + + + + + Error Scanning ADIF Log + + + + + Scanned ADIF log, %1 worked before records created + + + + + Error Loading LotW Users Data + + + + + Error Writing WAV File + + + + + Configurations... + + + + + Error Killing jt9.exe Process + + + + + KillByName return code: %1 + + + + + Error removing "%1" + + + + + Click OK to retry + + + + + + Improper mode + + + + + + File Open Error + + + + + + + + + Cannot open "%1" for append: %2 + + + + + Error saving c2 file + + + + + Error in Sound Input + + + + + Error in Sound Output + + + + + Change Operator + + + + + New operator: + + + + + Status File Error + + + + + + Cannot open "%1" for writing: %2 + + + + + Subprocess Error + + + + + Subprocess failed with exit code %1 + + + + + + Running: %1 +%2 + + + + + Subprocess error + + + + + Reference spectrum saved + + + + + Invalid data in fmt.all at line %1 + + + + + Good Calibration Solution + + + + + <pre>%1%L2 ±%L3 ppm +%4%L5 ±%L6 Hz + +%7%L8 +%9%L10 Hz</pre> + + + + + Delete Calibration Measurements + + + + + The "fmt.all" file will be renamed as "fmt.bak" + + + + + If you make fair use of any part of WSJT-X under terms of the GNU General Public License, you must display the following copyright notice prominently in your derivative work: + +"The algorithms, source code, look-and-feel of WSJT-X and related programs, and protocol specifications for the modes FSK441, FT8, JT4, JT6M, JT9, JT65, JTMS, QRA64, ISCAT, MSK144 are Copyright (C) 2001-2019 by one or more of the following authors: Joseph Taylor, K1JT; Bill Somerville, G4WJS; Steven Franke, K9AN; Nico Palermo, IV3NWV; Greg Beam, KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; Philip Karn, KA9Q; and other members of the WSJT Development Group." + + + + + No data read from disk. Wrong file format? + + + + + Confirm Delete + + + + + Are you sure you want to delete all *.wav and *.c2 files in "%1"? + + + + + Keyboard Shortcuts + + + + + Special Mouse Commands + + + + + No more files to open. + + + + + Please choose another Tx frequency. WSJT-X will not knowingly transmit another mode in the WSPR sub-band on 30m. + + + + + WSPR Guard Band + + + + + Please choose another dial frequency. WSJT-X will not operate in Fox mode in the standard FT8 sub-bands. + + + + + Fox Mode warning + + + + + Should you switch to ARRL Field Day mode? + + + + + Should you switch to RTTY contest mode? + + + + + + + + Add to CALL3.TXT + + + + + Please enter a valid grid locator + + + + + Cannot open "%1" for read/write: %2 + + + + + %1 +is already in CALL3.TXT, do you wish to replace it? + + + + + Warning: DX Call field is empty. + + + + + Log file error + + + + + Cannot open "%1" + + + + + Error sending log to N1MM + + + + + Write returned "%1" + + + + + + + Confirm Erase + + + + + Are you sure you want to erase file ALL.TXT? + + + + + + Confirm Reset + + + + + Are you sure you want to erase your contest log? + + + + + Doing this will remove all QSO records for the current contest. They will be kept in the ADIF log file but will not be available for export in your Cabrillo log. + + + + + Cabrillo Log saved + + + + + Are you sure you want to erase file wsjtx_log.adi? + + + + + Are you sure you want to erase the WSPR hashtable? + + + + + VHF features warning + + + + + Tune digital gain + + + + + Transmit digital gain + + + + + Prefixes + + + + + Network Error + + + + + Error: %1 +UDP server %2:%3 + + + + + File Error + + + + + Phase Training Disabled + + + + + Phase Training Enabled + + + + + + Log File Error + + + + + Are you sure you want to clear the QSO queues? + + + + + MessageAveraging + + + + Message Averaging + + + + + UTC Sync DT Freq + + + + + Modes + + + + Mode + + + + + MultiSettings + + + Default + + + + + MultiSettings::impl + + + &Switch To + + + + + &Clone + + + + + Clone &Into ... + + + + + R&eset + + + + + &Rename ... + + + + + &Delete + + + + + Clone Into Configuration + + + + + Confirm overwrite of all values for configuration "%1" with values from "%2"? + + + + + Reset Configuration + + + + + Confirm reset to default values for configuration "%1"? + + + + + Delete Configuration + + + + + Confirm deletion of configuration "%1"? + + + + + NameDialog + + + New Configuration Name + + + + + Old name: + + + + + &New name: + + + + + OmniRigTransceiver + + + OmniRig: unrecognized mode + + + + + Failed to start OmniRig COM server + + + + + + OmniRig: don't know how to set rig frequency + + + + + + OmniRig: timeout waiting for update from rig + + + + + OmniRig COM/OLE error: %1 at %2: %3 (%4) + + + + + PollingTransceiver + + + Unexpected rig error + + + + + QObject + + + Invalid rig name - \ & / not allowed + + + + + User Defined + + + + + Failed to open LotW users CSV file: '%1' + + + + + OOB + + + + + Too many colours in palette. + + + + + Error reading waterfall palette file "%1:%2" too many colors. + + + + + Error reading waterfall palette file "%1:%2" invalid triplet. + + + + + Error reading waterfall palette file "%1:%2" invalid color. + + + + + Error opening waterfall palette file "%1": %2. + + + + + Error writing waterfall palette file "%1": %2. + + + + + RemoteFile + + + + + + + + File System Error + + + + + Cannot rename file: +"%1" +to: "%2" +Error(%3): %4 + + + + + Cannot delete file: +"%1" + + + + + + + Network Error + + + + + Too many redirects: %1 + + + + + Redirect not followed: %1 + + + + + Cannot commit changes to: +"%1" + + + + + Cannot open file: +"%1" +Error(%2): %3 + + + + + Cannot make path: +"%1" + + + + + Cannot write to file: +"%1" +Error(%2): %3 + + + + + SampleDownloader::impl + + + Download Samples + + + + + Input Error + + + + + Invalid URL format + + + + + SoundInput + + + An error opening the audio input device has occurred. + + + + + An error occurred during read from the audio input device. + + + + + Audio data not being fed to the audio input device fast enough. + + + + + Non-recoverable error, audio input device not usable at this time. + + + + + Requested input audio format is not valid. + + + + + Requested input audio format is not supported on device. + + + + + Failed to initialize audio sink device + + + + + Idle + + + + + Receiving + + + + + Suspended + + + + + Interrupted + + + + + Error + + + + + Stopped + + + + + SoundOutput + + + An error opening the audio output device has occurred. + + + + + An error occurred during write to the audio output device. + + + + + Audio data not being fed to the audio output device fast enough. + + + + + Non-recoverable error, audio output device not usable at this time. + + + + + Requested output audio format is not valid. + + + + + Requested output audio format is not supported on device. + + + + + Idle + + + + + Sending + + + + + Suspended + + + + + Interrupted + + + + + Error + + + + + Stopped + + + + + StationDialog + + + Add Station + + + + + &Band: + + + + + &Offset (MHz): + + + + + &Antenna: + + + + + StationList::impl + + + Band name + + + + + Frequency offset + + + + + Antenna description + + + + + Band + + + + + Offset + + + + + Antenna Description + + + + + TransceiverBase + + + Unexpected rig error + + + + + WideGraph + + + Dialog + + + + + Controls + + + + + Spectrum gain + + + + + Palette + + + + + <html><head/><body><p>Enter definition for a new color palette.</p></body></html> + + + + + Adjust... + + + + + Waterfall gain + + + + + <html><head/><body><p>Set fractional size of spectrum in this window.</p></body></html> + + + + + % + + + + + Spec + + + + + <html><head/><body><p>Flatten spectral baseline over the full displayed interval.</p></body></html> + + + + + Flatten + + + + + <html><head/><body><p>Compute and save a reference spectrum. (Not yet fully implemented.)</p></body></html> + + + + + Ref Spec + + + + + Smoothing of Linear Average spectrum + + + + + Smooth + + + + + Compression factor for frequency scale + + + + + Bins/Pixel + + + + + Select waterfall palette + + + + + <html><head/><body><p>Select data for spectral display</p></body></html> + + + + + Current + + + + + Cumulative + + + + + Linear Avg + + + + + Reference + + + + + <html><head/><body><p>Frequency at left edge of waterfall</p></body></html> + + + + + Hz + + + + + Start + + + + + <html><head/><body><p>Decode JT9 only above this frequency</p></body></html> + + + + + JT9 + + + + + JT65 + + + + + Number of FFTs averaged (controls waterfall scrolling rate) + + + + + N Avg + + + + + Waterfall zero + + + + + Spectrum zero + + + + + Wide Graph + + + + + + Read Palette + + + + + configuration_dialog + + + Settings + + + + + Genera&l + + + + + General station details and settings. + + + + + Station Details + + + + + My C&all: + + + + + Station callsign. + + + + + M&y Grid: + + + + + <html><head/><body><p>Maidenhead locator, preferably 6 characters.</p></body></html> + + + + + Check to allow grid changes from external programs + + + + + AutoGrid + + + + + IARU Region: + + + + + <html><head/><body><p>Select your IARU region.</p></body></html> + + + + + Message generation for type 2 compound callsign holders: + + + + + <html><head/><body><p>Type 2 compound callsigns are those with prefixes or suffixes not included in the allowed shortlist (See Help-&gt;Add-on prefixes and suffixes).</p><p>This option determines which generated messages should contain your full type 2 compound call sign rather than your base callsign. It only applies if you have a type 2 compound callsign.</p><p>This option controls the way the messages that are used to answer CQ calls are generated. Generated messages 6 (CQ) and 5 (73) will always contain your full callsign. The JT65 and JT9 protocols allow for some standard messages with your full call at the expense of another piece of information such as the DX call or your locator.</p><p>Choosing message 1 omits the DX callsign which may be an issue when replying to CQ calls. Choosing message 3 also omits the DX callsign and many versions of this and other software will not extract the report. Choosing neither means that your full callsign only goes in your message 5 (73) so your QSO partner may log the wrong callsign.</p><p>None of these options are perfect, message 3 is usually best but be aware your QSO partner may not log the report you send them.</p></body></html> + + + + + Full call in Tx1 + + + + + Full call in Tx3 + + + + + Full call in Tx5 only + + + + + Display + + + + + Show outgoing transmitted messages in the Rx frequency window. + + + + + &Tx messages to Rx frequency window + + + + + Show if decoded stations are new DXCC entities or worked before. + + + + + Show &DXCC, grid, and worked-before status + + + + + <html><head/><body><p>Check to have decodes for a new period start at the top of the Band Activity window and not scroll off the top when the window is full.</p><p>This is to aid selecting decodes to double-click while decoding is still in progress. Use the Band Activity vertical scroll bar to reveal decodes past the bottom of the window.</p></body></html> + + + + + Start new period decodes at top + + + + + Show principal prefix instead of country name + + + + + Set the font characteristics for the application. + + + + + Font... + + + + + Set the font characteristics for the Band Activity and Rx Frequency areas. + + + + + Decoded Text Font... + + + + + Include a separator line between periods in the band activity window. + + + + + &Blank line between decoding periods + + + + + Show distance to DX station in miles rather than kilometers. + + + + + Display dista&nce in miles + + + + + Behavior + + + + + Decode after EME delay + + + + + Tx watchdog: + + + + + <html><head/><body><p>Number of minutes before unattended transmissions are aborted</p></body></html> + + + + + Disabled + + + + + minutes + + + + + Enable VHF/UHF/Microwave features + + + + + Single decode + + + + + <html><head/><body><p>Some rigs are not able to process CAT commands while transmitting. This means that if you are operating in split mode you may have to uncheck this option.</p></body></html> + + + + + Allow Tx frequency changes while transmitting + + + + + Don't start decoding until the monitor button is clicked. + + + + + Mon&itor off at startup + + + + + <html><head/><body><p>Check this if you wish to automatically return to the last monitored frequency when monitor is enabled, leave it unchecked if you wish to have the current rig frequency maintained.</p></body></html> + + + + + Monitor returns to last used frequency + + + + + Alternate F1-F6 bindings + + + + + Turns off automatic transmissions after sending a 73 or any other free +text message. + + + + + Di&sable Tx after sending 73 + + + + + Send a CW ID after every 73 or free text message. + + + + + CW ID a&fter 73 + + + + + Periodic CW ID Inter&val: + + + + + Send a CW ID periodically every few minutes. +This might be required under your countries licence regulations. +It will not interfere with other users as it is always sent in the +quiet period when decoding is done. + + + + + Automatic transmission mode. + + + + + Doubl&e-click on call sets Tx enable + + + + + Calling CQ forces Call 1st + + + + + &Radio + + + + + Radio interface configuration settings. + + + + + Settings that control your CAT interface. + + + + + CAT Control + + + + + + Port: + + + + + Serial port used for CAT control. + + + + + Serial Port Parameters + + + + + Baud Rate: + + + + + Serial port data rate which must match the setting of your radio. + + + + + 1200 + + + + + 2400 + + + + + 4800 + + + + + 9600 + + + + + 19200 + + + + + 38400 + + + + + 57600 + + + + + 115200 + + + + + <html><head/><body><p>Number of data bits used to communicate with your radio's CAT interface (usually eight).</p></body></html> + + + + + Data Bits + + + + + D&efault + + + + + Se&ven + + + + + E&ight + + + + + <html><head/><body><p>Number of stop bits used when communicating with your radio's CAT interface</p><p>(consult you radio's manual for details).</p></body></html> + + + + + Stop Bits + + + + + + Default + + + + + On&e + + + + + T&wo + + + + + <html><head/><body><p>Flow control protocol used between this computer and your radio's CAT interface (usually &quot;None&quot; but some require &quot;Hardware&quot;).</p></body></html> + + + + + Handshake + + + + + &None + + + + + Software flow control (very rare on CAT interfaces). + + + + + XON/XOFF + + + + + Flow control using the RTS and CTS RS-232 control lines +not often used but some radios have it as an option and +a few, particularly some Kenwood rigs, require it). + + + + + &Hardware + + + + + Special control of CAT port control lines. + + + + + Force Control Lines + + + + + + High + + + + + + Low + + + + + DTR: + + + + + RTS: + + + + + How this program activates the PTT on your radio + + + + + PTT Method + + + + + <html><head/><body><p>No PTT activation, instead the radio's automatic VOX is used to key the transmitter.</p><p>Use this if you have no radio interface hardware.</p></body></html> + + + + + VO&X + + + + + <html><head/><body><p>Use the RS-232 DTR control line to toggle your radio's PTT, requires hardware to inteface the line.</p><p>Some commercial interface units also use this method.</p><p>The DTR control line of the CAT serial port may be used for this or a DTR control line on a different serial port may be used.</p></body></html> + + + + + &DTR + + + + + Some radios support PTT via CAT commands, +use this option if your radio supports it and you have no +other hardware interface for PTT. + + + + + C&AT + + + + + <html><head/><body><p>Use the RS-232 RTS control line to toggle your radio's PTT, requires hardware to inteface the line.</p><p>Some commercial interface units also use this method.</p><p>The RTS control line of the CAT serial port may be used for this or a RTS control line on a different serial port may be used. Note that this option is not available on the CAT serial port when hardware flow control is used.</p></body></html> + + + + + R&TS + + + + + <html><head/><body><p>Select the RS-232 serial port utilised for PTT control, this option is available when DTR or RTS is selected above as a transmit method.</p><p>This port can be the same one as the one used for CAT control.</p><p>For some interface types the special value CAT may be chosen, this is used for non-serial CAT interfaces that can control serial port control lines remotely (OmniRig for example).</p></body></html> + + + + + Modulation mode selected on radio. + + + + + Mode + + + + + <html><head/><body><p>USB is usually the correct modulation mode,</p><p>unless the radio has a special data or packet mode setting</p><p>for AFSK operation.</p></body></html> + + + + + US&B + + + + + Don't allow the program to set the radio mode +(not recommended but use if the wrong mode +or bandwidth is selected). + + + + + + None + + + + + If this is availabe then it is usually the correct mode for this program. + + + + + Data/P&kt + + + + + Some radios can select the audio input using a CAT command, +this setting allows you to select which audio input will be used +(if it is available then generally the Rear/Data option is best). + + + + + Transmit Audio Source + + + + + Rear&/Data + + + + + &Front/Mic + + + + + Rig: + + + + + Poll Interval: + + + + + <html><head/><body><p>Interval to poll rig for status. Longer intervals will mean that changes to the rig will take longer to be detected.</p></body></html> + + + + + s + + + + + <html><head/><body><p>Attempt to connect to the radio with these settings.</p><p>The button will turn green if the connection is successful or red if there is a problem.</p></body></html> + + + + + Test CAT + + + + + Attempt to activate the transmitter. +Click again to deactivate. Normally no power should be +output since there is no audio being generated at this time. +Check that any Tx indication on your radio and/or your +radio interface behave as expected. + + + + + Test PTT + + + + + Split Operation + + + + + Fake It + + + + + Rig + + + + + A&udio + + + + + Audio interface settings + + + + + Souncard + + + + + Soundcard + + + + + 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. + + + + + Select the audio CODEC to use for receiving. + + + + + &Input: + + + + + Select the channel to use for receiving. + + + + + + Mono + + + + + + Left + + + + + + Right + + + + + + Both + + + + + Select the audio channel used for transmission. +Unless you have multiple radios connected on different +channels; then you will usually want to select mono or +both here. + + + + + Ou&tput: + + + + + + Save Directory + + + + + Loc&ation: + + + + + Path to which .WAV files are saved. + + + + + + TextLabel + + + + + Click to select a different save directory for .WAV files. + + + + + S&elect + + + + + + AzEl Directory + + + + + Location: + + + + + Select + + + + + Power Memory By Band + + + + + Remember power settings by band + + + + + Enable power memory during transmit + + + + + Transmit + + + + + Enable power memory during tuning + + + + + Tune + + + + + Tx &Macros + + + + + Canned free text messages setup + + + + + &Add + + + + + &Delete + + + + + Drag and drop items to rearrange order +Right click for item specific actions +Click, SHIFT+Click and, CRTL+Click to select items + + + + + Reportin&g + + + + + Reporting and logging settings + + + + + Logging + + + + + The program will pop up a partially completed Log QSO dialog when you send a 73 or free text message. + + + + + Promp&t me to log QSO + + + + + Op Call: + + + + + Some logging programs will not accept the type of reports +saved by this program. +Check this option to save the sent and received reports in the +comments field. + + + + + d&B reports to comments + + + + + Check this option to force the clearing of the DX Call +and DX Grid fields when a 73 or free text message is sent. + + + + + Clear &DX call and grid after logging + + + + + <html><head/><body><p>Some logging programs will not accept WSJT-X mode names.</p></body></html> + + + + + Con&vert mode to RTTY + + + + + <html><head/><body><p>The callsign of the operator, if different from the station callsign.</p></body></html> + + + + + <html><head/><body><p>Check to have QSOs logged automatically, when complete.</p></body></html> + + + + + Log automatically (contesting only) + + + + + Network Services + + + + + The program can send your station details and all +decoded signals as spots to the http://pskreporter.info web site. +This is used for reverse beacon analysis which is very useful +for assessing propagation and system performance. + + + + + Enable &PSK Reporter Spotting + + + + + UDP Server + + + + + UDP Server: + + + + + <html><head/><body><p>Optional hostname of network service to receive decodes.</p><p>Formats:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 multicast group address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 multicast group address</li></ul><p>Clearing this field will disable the broadcasting of UDP status updates.</p></body></html> + + + + + UDP Server port number: + + + + + <html><head/><body><p>Enter the service port number of the UDP server that WSJT-X should send updates to. If this is zero no updates will be broadcast.</p></body></html> + + + + + <html><head/><body><p>With this enabled WSJT-X will accept certain requests back from a UDP server that receives decode messages.</p></body></html> + + + + + Accept UDP requests + + + + + <html><head/><body><p>Indicate acceptance of an incoming UDP request. The effect of this option varies depending on the operating system and window manager, its intent is to notify the acceptance of an incoming UDP request even if this application is minimized or hidden.</p></body></html> + + + + + Notify on accepted UDP request + + + + + <html><head/><body><p>Restore the window from minimized if an UDP request is accepted.</p></body></html> + + + + + Accepted UDP request restores window + + + + + Secondary UDP Server (deprecated) + + + + + <html><head/><body><p>When checked, WSJT-X will broadcast a logged contact in ADIF format to the configured hostname and port. </p></body></html> + + + + + Enable logged contact ADIF broadcast + + + + + Server name or IP address: + + + + + <html><head/><body><p>Optional host name of N1MM Logger+ program to receive ADIF UDP broadcasts. This is usually 'localhost' or ip address 127.0.0.1</p><p>Formats:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 multicast group address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 multicast group address</li></ul><p>Clearing this field will disable broadcasting of ADIF information via UDP.</p></body></html> + + + + + Server port number: + + + + + <html><head/><body><p>Enter the port number that WSJT-X should use for UDP broadcasts of ADIF log information. For N1MM Logger+, this value should be 2333. If this is zero, no updates will be broadcast.</p></body></html> + + + + + Frequencies + + + + + Default frequencies and band specific station details setup + + + + + <html><head/><body><p>See &quot;Frequency Calibration&quot; in the WSJT-X User Guide for details of how to determine these parameters for your radio.</p></body></html> + + + + + Frequency Calibration + + + + + Slope: + + + + + ppm + + + + + Intercept: + + + + + Hz + + + + + Working Frequencies + + + + + <html><head/><body><p>Right click to maintain the working frequencies list.</p></body></html> + + + + + Station Information + + + + + Items may be edited. +Right click for insert and delete options. + + + + + Colors + Colours + + + + Decode Highlightling + + + + + <html><head/><body><p>Enable or disable using the check boxes and right-click an item to change or unset the foreground color, background color, or reset the item to default values. Drag and drop the items to change their priority, higher in the list is higher in priority.</p><p>Note that each foreground or background color may be either set or unset, unset means that it is not allocated for that item's type and lower priority items may apply.</p></body></html> + + + + + <html><head/><body><p>Push to reset all highlight items above to default values and priorities.</p></body></html> + + + + + Reset Highlighting + + + + + <html><head/><body><p>Check to indicate new DXCC entities, grid squares, and callsigns per mode.</p></body></html> + + + + + Highlight by Mode + + + + + <html><head/><body><p>Click to scan the wsjtx_log.adi ADIF file again for worked before information</p></body></html> + + + + + Rescan ADIF Log + + + + + Include extra WAE entities + + + + + <html><head/><body><p>Controls for Logbook of the World user lookup.</p></body></html> + + + + + Logbook of the World User Validation + + + + + Users CSV file URL: + + + + + <html><head/><body><p>URL of the ARRL LotW user's last upload dates and times data file which is used to highlight decodes from stations that are known to upload their log file to LotW.</p></body></html> + + + + + https://lotw.arrl.org/lotw-user-activity.csv + + + + + <html><head/><body><p>Push this button to fetch the latest LotW user's upload date and time data file.</p></body></html> + + + + + Fetch Now + + + + + Age of last upload less than: + + + + + <html><head/><body><p>Adjust this spin box to set the age threshold of LotW user's last upload date that is accepted as a current LotW user.</p></body></html> + + + + + days + + + + + Advanced + + + + + <html><head/><body><p>User-selectable parameters for JT65 VHF/UHF/Microwave decoding.</p></body></html> + + + + + JT65 VHF/UHF/Microwave decoding parameters + + + + + Random erasure patterns: + + + + + <html><head/><body><p>Maximum number of erasure patterns for stochastic soft-decision Reed Solomon decoder is 10^(n/2).</p></body></html> + + + + + Aggressive decoding level: + + + + + <html><head/><body><p>Higher levels will increase the probability of decoding, but will also increase probability of a false decode.</p></body></html> + + + + + Two-pass decoding + + + + + Special operating activity: Generation of FT4, FT8, and MSK144 messages + + + + + <html><head/><body><p>FT8 DXpedition mode: Hound operator calling the DX.</p></body></html> + + + + + Hound + + + + + <html><head/><body><p>North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.</p></body></html> + + + + + NA VHF Contest + + + + + <html><head/><body><p>FT8 DXpedition mode: Fox (DXpedition) operator.</p></body></html> + + + + + Fox + + + + + <html><head/><body><p>European VHF+ contests requiring a signal report, serial number, and 6-character locator.</p></body></html> + + + + + EU VHF Contest + + + + + + <html><head/><body><p>ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html> + + + + + RTTY Roundup messages + + + + + RTTY RU Exch: + + + + + NJ + + + + + + <html><head/><body><p>ARRL Field Day exchange: number of transmitters, Class, and ARRL/RAC section or &quot;DX&quot;.</p></body></html> + + + + + ARRL Field Day + + + + + FD Exch: + + + + + 6A SNJ + + + + + Miscellaneous + + + + + Degrade S/N of .wav file: + + + + + + For offline sensitivity tests + + + + + dB + + + + + Receiver bandwidth: + + + + + Hz + + + + + Tx delay: + + + + + Minimum delay between assertion of PTT and start of Tx audio. + + + + + s + + + + + Tone spacing + + + + + <html><head/><body><p>Generate Tx audio with twice the normal tone spacing. Intended for special LF/MF transmitters that use a divide-by-2 before generating RF.</p></body></html> + + + + + x 2 + + + + + <html><head/><body><p>Generate Tx audio with four times the normal tone spacing. Intended for special LF/MF transmitters that use a divide-by-4 before generating RF.</p></body></html> + + + + + x 4 + + + + + Waterfall spectra + + + + + Low sidelobes + + + + + Most sensitive + + + + + <html><head/><body><p>Discard (Cancel) or apply (OK) configuration changes including</p><p>resetting the radio interface and applying any soundcard changes</p></body></html> + + + + + main + + + + Fatal error + + + + + + Unexpected fatal error + + + + + Where <rig-name> is for multi-instance support. + + + + + rig-name + + + + + Where <configuration> is an existing one. + + + + + configuration + + + + + Writable files in test location. Use with caution, for testing only. + + + + + Command line error + + + + + Command line help + + + + + Application version + + + + + Another instance may be running + + + + + try to remove stale lock file? + + + + + Failed to create a temporary directory + + + + + + Path: "%1" + + + + + Failed to create a usable temporary directory + + + + + Another application may be locking the directory + + + + + Failed to create data directory + + + + + path: "%1" + + + + + Shared memory error + + + + + Unable to create shared memory segment + + + + + wf_palette_design_dialog + + + Palette Designer + + + + + <html><head/><body><p>Double click a color to edit it.</p><p>Right click to insert or delete colors.</p><p>Colors at the top represent weak signals</p><p>and colors at the bottom represent strong</p><p>signals. You can have up to 256 colors.</p></body></html> + + + + diff --git a/translations/wsjtx_pt_PT.ts b/translations/wsjtx_pt_PT.ts new file mode 100644 index 000000000..6167f5d8d --- /dev/null +++ b/translations/wsjtx_pt_PT.ts @@ -0,0 +1,6007 @@ + + + + + AbstractLogWindow + + + &Delete ... + + + + + AbstractLogWindow::impl + + + Confirm Delete + + + + + Are you sure you want to delete the %n selected QSO(s) from the log + + + + + + + + Astro + + + + Doppler tracking + + + + + <html><head/><body><p>One station does all Doppler shift correction, their QSO partner receives and transmits on the sked frequency.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p></body></html> + + + + + Full Doppler to DX Grid + + + + + <html><head/><body><p>Transmit takes place on sked frequency and receive frequency is corrected for own echoes. </p><p>This mode can be used for calling CQ, or when using Echo mode.</p></body></html> + + + + + Own Echo + + + + + <html><head/><body><p>Both stations correct for Doppler shift such that they would be heard on the moon at the sked frequency.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p><p>Use this option also for Echo mode.</p></body></html> + + + + + Constant frequency on Moon + + + + + <html><head/><body><p>DX station announces their TX Freq, which is entered as the Sked Freq. Correction applied to RX and TX so you appear on the DX's station's own echo Freq.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p></body></html> + + + + + On DX Echo + + + + + <html><head/><body><p>Tune radio manually and select this mode to put your echo on the same frequency.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p></body></html> + + + + + Call DX + + + + + <html><head/><body><p>No Doppler shift correction is applied. This may be used when the QSO partner does full Doppler correction to your grid square.</p></body></html> + + + + + None + + + + + Sked frequency + + + + + + 0 + + + + + Rx: + + + + + Tx: + + + + + <html><head/><body><p>Press and hold the CTRL key to adjust the sked frequency manually with the rig's VFO dial or enter frequency directly into the band entry field on the main window.</p></body></html> + + + + + Astro Data + + + + + Astronomical Data + + + + + Doppler Tracking Error + + + + + Split operating is required for Doppler tracking + + + + + Go to "Menu->File->Settings->Radio" to enable split operation + + + + + Bands + + + Band name + + + + + Lower frequency limit + + + + + Upper frequency limit + + + + + Band + + + + + Lower Limit + + + + + Upper Limit + + + + + CAboutDlg + + + About WSJT-X + + + + + OK + + + + + CPlotter + + + &Set Rx && Tx Offset + + + + + CabrilloLog + + + Freq(MHz) + + + + + Mode + + + + + Date & Time(UTC) + + + + + Call + + + + + Sent + + + + + Rcvd + + + + + Band + + + + + CabrilloLogWindow + + + Contest Log + + + + + <html><head/><body><p>Right-click here for available actions.</p></body></html> + + + + + Right-click here for available actions. + + + + + CallsignDialog + + + Callsign + + + + + ColorHighlighting + + + + + + + + + + + + + + + + + + K1ABC + + + + + CQ in message + + + + + My Call in message + + + + + Transmitted message + + + + + New DXCC + + + + + New Grid + + + + + New DXCC on Band + + + + + New Call + + + + + New Grid on Band + + + + + New Call on Band + + + + + Uploads to LotW + + + + + New Continent + + + + + New Continent on Band + + + + + New CQ Zone + + + + + New CQ Zone on Band + + + + + New ITU Zone + + + + + New ITU Zone on Band + + + + + Configuration::impl + + + + + &Delete + + + + + + &Insert ... + + + + + Failed to create save directory + + + + + path: "%1% + + + + + Failed to create samples directory + + + + + path: "%1" + + + + + &Load ... + + + + + &Save as ... + + + + + &Merge ... + + + + + &Reset + + + + + Serial Port: + + + + + Serial port used for CAT control + + + + + Network Server: + + + + + Optional hostname and port of network service. +Leave blank for a sensible default on this machine. +Formats: + hostname:port + IPv4-address:port + [IPv6-address]:port + + + + + USB Device: + + + + + Optional device identification. +Leave blank for a sensible default for the rig. +Format: + [VID[:PID[:VENDOR[:PRODUCT]]]] + + + + + Invalid audio input device + + + + + Invalid audio out device + + + + + Invalid PTT method + + + + + Invalid PTT port + + + + + + Invalid Contest Exchange + + + + + You must input a valid ARRL Field Day exchange + + + + + You must input a valid ARRL RTTY Roundup exchange + + + + + Reset Decode Highlighting + + + + + Reset all decode highlighting and priorities to default values + + + + + WSJT-X Decoded Text Font Chooser + + + + + Load Working Frequencies + + + + + + + Frequency files (*.qrg);;All files (*.*) + + + + + Replace Working Frequencies + + + + + Are you sure you want to discard your current working frequencies and replace them with the loaded ones? + + + + + Merge Working Frequencies + + + + + + + Not a valid frequencies file + + + + + Incorrect file magic + + + + + Version is too new + + + + + Contents corrupt + + + + + Save Working Frequencies + + + + + Only Save Selected Working Frequencies + + + + + Are you sure you want to save only the working frequencies that are currently selected? Click No to save all. + + + + + Reset Working Frequencies + + + + + Are you sure you want to discard your current working frequencies and replace them with default ones? + + + + + Save Directory + + + + + AzEl Directory + + + + + Rig control error + + + + + Failed to open connection to rig + + + + + Rig failure + + + + + DXLabSuiteCommanderTransceiver + + + Failed to connect to DX Lab Suite Commander + + + + + + DX Lab Suite Commander didn't respond correctly reading frequency: + + + + + DX Lab Suite Commander sent an unrecognised TX state: + + + + + DX Lab Suite Commander didn't respond correctly polling TX status: + + + + + DX Lab Suite Commander rig did not respond to PTT: + + + + + DX Lab Suite Commander didn't respond correctly polling frequency: + + + + + DX Lab Suite Commander didn't respond correctly polling TX frequency: + + + + + DX Lab Suite Commander sent an unrecognised split state: + + + + + DX Lab Suite Commander didn't respond correctly polling split status: + + + + + DX Lab Suite Commander sent an unrecognised mode: " + + + + + DX Lab Suite Commander didn't respond correctly polling mode: + + + + + DX Lab Suite Commander send command failed + + + + + + DX Lab Suite Commander failed to send command "%1": %2 + + + + + + DX Lab Suite Commander send command "%1" read reply failed: %2 + + + + + + DX Lab Suite Commander retries exhausted sending command "%1" + + + + + DX Lab Suite Commander sent an unrecognized frequency + + + + + DecodeHighlightingListView + + + &Foreground color ... + + + + + Choose %1 Foreground Color + + + + + &Unset foreground color + + + + + &Background color ... + + + + + Choose %1 Background Color + + + + + U&nset background color + + + + + &Reset this item to defaults + + + + + DecodeHighlightingModel + + + Highlight Type + + + + + Designer + + + &Delete + + + + + &Insert ... + + + + + Insert &after ... + + + + + Import Palette + + + + + + Palettes (*.pal) + + + + + Export Palette + + + + + Dialog + + + Gray time: + + + + + Directory + + + + URL Error + + + + + + Invalid URL: +"%1" + + + + + + + + + + + JSON Error + + + + + Contents file syntax error %1 at character offset %2 + + + + + Contents file top level must be a JSON array + + + + + File System Error + + + + + Failed to open "%1" +Error: %2 - %3 + + + + + Contents entries must be a JSON array + + + + + Contents entries must have a valid type + + + + + Contents entries must have a valid name + + + + + Contents entries must be JSON objects + + + + + Contents directories must be relative and within "%1" + + + + + Network Error + + + + + Authentication required + + + + + DisplayText + + + &Erase + + + + + EchoGraph + + + + Echo Graph + + + + + <html><head/><body><p>Compression factor for frequency scale</p></body></html> + + + + + Bins/Pixel + + + + + Gain + + + + + <html><head/><body><p>Echo spectrum gain</p></body></html> + + + + + Zero + + + + + <html><head/><body><p>Echo spectrum zero</p></body></html> + + + + + <html><head/><body><p>Smoothing of echo spectrum</p></body></html> + + + + + Smooth + + + + + <html><head/><body><p>Number of echo transmissions averaged</p></body></html> + + + + + N: 0 + + + + + <html><head/><body><p>Click to cycle through a sequence of colors and line widths.</p></body></html> + + + + + Colors + Cores + + + + EmulateSplitTransceiver + + + Emulated split mode requires rig to be in simplex mode + + + + + EqualizationToolsDialog::impl + + + Phase + + + + + + Freq (Hz) + + + + + Phase (Π) + + + + + Delay (ms) + + + + + Measured + + + + + Proposed + + + + + Current + + + + + Group Delay + + + + + Amplitude + + + + + Relative Power (dB) + + + + + Reference + + + + + Phase ... + + + + + Refresh + + + + + Discard Measured + + + + + ExistingNameDialog + + + Configuration to Clone From + + + + + &Source Configuration Name: + + + + + ExportCabrillo + + + Dialog + + + + + Location: + + + + + SNJ + + + + + Contest: + + + + + ARRL-RTTY + + + + + Callsign: + + + + + Category-Operator: + + + + + SINGLE-OP + + + + + Category-Transmitter: + + + + + ONE + + + + + Category-Power: + + + + + LOW + + + + + Category-Assisted: + + + + + NON-ASSISTED + + + + + Category-Band: + + + + + ALL + + + + + Claimed-Score: + + + + + Operators: + + + + + Club: + + + + + Name: + + + + + + Address: + + + + + Save Log File + + + + + Cabrillo Log (*.cbr) + + + + + Cannot open "%1" for writing: %2 + + + + + Export Cabrillo File Error + + + + + FastGraph + + + + Fast Graph + + + + + Waterfall gain + + + + + Waterfall zero + + + + + Spectrum zero + + + + + <html><head/><body><p>Set reasonable levels for gain and zero sliders.</p></body></html> + + + + + Auto Level + + + + + FoxLog::impl + + + Date & Time(UTC) + + + + + Call + + + + + Grid + + + + + Sent + + + + + Rcvd + + + + + Band + + + + + FoxLogWindow + + + Fox Log + + + + + <html><head/><body><p>Right-click here for available actions.</p></body></html> + + + + + Callers: + + + + + + + N + + + + + In progress: + + + + + Rate: + + + + + &Export ADIF ... + + + + + Export ADIF Log File + + + + + ADIF Log (*.adi) + + + + + Export ADIF File Error + + + + + Cannot open "%1" for writing: %2 + + + + + &Reset ... + + + + + Confirm Reset + + + + + Are you sure you want to erase file FoxQSO.txt and start a new Fox log? + + + + + FrequencyDialog + + + Add Frequency + + + + + IARU &Region: + + + + + &Mode: + + + + + &Frequency (MHz): + + + + + FrequencyList_v2 + + + + IARU Region + + + + + + Mode + + + + + + Frequency + + + + + + Frequency (MHz) + + + + + HRDTransceiver + + + + Failed to connect to Ham Radio Deluxe + + + + + + Failed to open file "%1": %2. + + + + + + Ham Radio Deluxe: no rig found + + + + + Ham Radio Deluxe: rig doesn't support mode + + + + + Ham Radio Deluxe: sent an unrecognised mode + + + + + Ham Radio Deluxe: item not found in %1 dropdown list + + + + + Ham Radio Deluxe: button not available + + + + + Ham Radio Deluxe didn't respond as expected + + + + + Ham Radio Deluxe: rig has disappeared or changed + + + + + Ham Radio Deluxe send command "%1" failed %2 + + + + + + + Ham Radio Deluxe: failed to write command "%1" + + + + + Ham Radio Deluxe sent an invalid reply to our command "%1" + + + + + Ham Radio Deluxe failed to reply to command "%1" %2 + + + + + + Ham Radio Deluxe retries exhausted sending command "%1" + + + + + Ham Radio Deluxe didn't respond to command "%1" as expected + + + + + HamlibTransceiver + + + + Hamlib initialisation error + + + + + Hamlib settings file error: %1 at character offset %2 + + + + + Hamlib settings file error: top level must be a JSON object + + + + + Hamlib settings file error: config must be a JSON object + + + + + Unsupported CAT type + + + + + Hamlib error: %1 while %2 + + + + + opening connection to rig + + + + + getting current frequency + + + + + getting current mode + + + + + + exchanging VFOs + + + + + + getting other VFO frequency + + + + + getting other VFO mode + + + + + setting current VFO + + + + + getting frequency + + + + + getting mode + + + + + + getting current VFO + + + + + + + + getting current VFO frequency + + + + + + + + + + setting frequency + + + + + + + + getting current VFO mode + + + + + + + + + setting current VFO mode + + + + + + setting/unsetting split mode + + + + + + setting split mode + + + + + setting split TX frequency and mode + + + + + setting split TX frequency + + + + + getting split TX VFO mode + + + + + setting split TX VFO mode + + + + + getting PTT state + + + + + setting PTT on + + + + + setting PTT off + + + + + setting a configuration item + + + + + getting a configuration item + + + + + HelpTextWindow + + + Help file error + + + + + Cannot open "%1" for reading + + + + + Error: %1 + + + + + IARURegions + + + + IARU Region + + + + + LogQSO + + + Click OK to confirm the following QSO: + + + + + Call + + + + + Start + + + + + + dd/MM/yyyy HH:mm:ss + + + + + End + + + + + Mode + + + + + Band + + + + + Rpt Sent + + + + + Rpt Rcvd + + + + + Grid + + + + + Name + + + + + Tx power + + + + + + Retain + + + + + Comments + + + + + Operator + + + + + Exch sent + + + + + Rcvd + + + + + + Invalid QSO Data + + + + + Check exchange sent and received + + + + + Check all fields + + + + + Log file error + + + + + Cannot open "%1" for append + + + + + Error: %1 + + + + + LotWUsers::impl + + + Network Error - SSL/TLS support not installed, cannot fetch: +'%1' + + + + + Network Error - Too many redirects: +'%1' + + + + + Network Error: +%1 + + + + + File System Error - Cannot commit changes to: +"%1" + + + + + File System Error - Cannot open file: +"%1" +Error(%2): %3 + + + + + File System Error - Cannot write to file: +"%1" +Error(%2): %3 + + + + + MainWindow + + + WSJT-X by K1JT + + + + + Band Activity + + + + + + UTC dB DT Freq Dr + + + + + Rx Frequency + + + + + CQ only + + + + + Enter this QSO in log + + + + + Log &QSO + + + + + Stop monitoring + + + + + &Stop + + + + + Toggle monitoring On/Off + + + + + &Monitor + + + + + <html><head/><body><p>Erase right window. Double-click to erase both windows.</p></body></html> + + + + + Erase right window. Double-click to erase both windows. + + + + + &Erase + + + + + <html><head/><body><p>Clear the accumulating message average.</p></body></html> + + + + + Clear the accumulating message average. + + + + + Clear Avg + + + + + <html><head/><body><p>Decode most recent Rx period at QSO Frequency</p></body></html> + + + + + Decode most recent Rx period at QSO Frequency + + + + + &Decode + + + + + <html><head/><body><p>Toggle Auto-Tx On/Off</p></body></html> + + + + + Toggle Auto-Tx On/Off + + + + + E&nable Tx + + + + + Stop transmitting immediately + + + + + &Halt Tx + + + + + <html><head/><body><p>Toggle a pure Tx tone On/Off</p></body></html> + + + + + Toggle a pure Tx tone On/Off + + + + + &Tune + + + + + Menus + + + + + USB dial frequency + + + + + 14.078 000 + + + + + <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> + + + + + Rx Signal + + + + + 30dB recommended when only noise present +Green when good +Red when clipping may occur +Yellow when too low + + + + + DX Call + + + + + DX Grid + + + + + Callsign of station to be worked + + + + + Search for callsign in database + + + + + &Lookup + + + + + Locator of station to be worked + + + + + Az: 251 16553 km + + + + + Add callsign and locator to database + + + + + Add + + + + + Pwr + + + + + <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> + + + + + If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode. + + + + + ? + + + + + Adjust Tx audio level + + + + + <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html> + + + + + Frequncy entry + + + + + Select operating band or enter frequency in MHz or enter kHz increment followed by k. + + + + + <html><head/><body><p align="center"> 2015 Jun 17 </p><p align="center"> 01:23:45 </p></body></html> + + + + + <html><head/><body><p>Check to keep Tx frequency fixed when double-clicking on decoded text.</p></body></html> + + + + + Check to keep Tx frequency fixed when double-clicking on decoded text. + + + + + Hold Tx Freq + + + + + Audio Rx frequency + + + + + + + Hz + + + + + Rx + + + + + Set Tx frequency to Rx Frequency + + + + + â–² + + + + + Frequency tolerance (Hz) + + + + + F Tol + + + + + Set Rx frequency to Tx Frequency + + + + + â–¼ + + + + + <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> + + + + + Synchronizing threshold. Lower numbers accept weaker sync signals. + + + + + Sync + + + + + <html><head/><body><p>Check to use short-format messages.</p></body></html> + + + + + Check to use short-format messages. + + + + + Sh + + + + + <html><head/><body><p>Check to enable JT9 fast modes</p></body></html> + + + + + Check to enable JT9 fast modes + + + + + + Fast + + + + + <html><head/><body><p>Check to enable automatic sequencing of Tx messages based on received messages.</p></body></html> + + + + + Check to enable automatic sequencing of Tx messages based on received messages. + + + + + Auto Seq + + + + + <html><head/><body><p>Check to call the first decoded responder to my CQ.</p></body></html> + + + + + Check to call the first decoded responder to my CQ. + + + + + Call 1st + + + + + Check to generate "@1250 (SEND MSGS)" in Tx6. + + + + + Tx6 + + + + + <html><head/><body><p>Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences.</p></body></html> + + + + + Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences. + + + + + Tx even/1st + + + + + <html><head/><body><p>Frequency to call CQ on in kHz above the current MHz</p></body></html> + + + + + Frequency to call CQ on in kHz above the current MHz + + + + + Tx CQ + + + + + <html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to nonstandard callsign holders.</p></body></html> + + + + + Check this to call CQ on the "Tx CQ" frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on. +Not available to nonstandard callsign holders. + + + + + Rx All Freqs + + + + + <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> + + + + + Submode determines tone spacing; A is narrowest. + + + + + Submode + + + + + Fox + + + + + <html><head/><body><p>Check to monitor Sh messages.</p></body></html> + + + + + Check to monitor Sh messages. + + + + + SWL + + + + + Best S+P + + + + + <html><head/><body><p>Check this to start recording calibration data.<br/>While measuring calibration correction is disabled.<br/>When not checked you can view the calibration results.</p></body></html> + + + + + Check this to start recording calibration data. +While measuring calibration correction is disabled. +When not checked you can view the calibration results. + + + + + Measure + + + + + <html><head/><body><p>Signal report: Signal-to-noise ratio in 2500 Hz reference bandwidth (dB).</p></body></html> + + + + + Signal report: Signal-to-noise ratio in 2500 Hz reference bandwidth (dB). + + + + + Report + + + + + <html><head/><body><p>Tx/Rx or Frequency calibration sequence length</p></body></html> + + + + + Tx/Rx or Frequency calibration sequence length + + + + + s + + + + + T/R + + + + + Toggle Tx mode + + + + + Tx JT9 @ + + + + + Audio Tx frequency + + + + + + Tx + + + + + Tx# + + + + + <html><head/><body><p>Double-click on another caller to queue that call for your next QSO.</p></body></html> + + + + + Double-click on another caller to queue that call for your next QSO. + + + + + Next Call + + + + + 1 + + + + + + + Send this message in next Tx interval + + + + + Ctrl+2 + + + + + <html><head/><body><p>Send this message in next Tx interval</p><p>Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders)</p></body></html> + + + + + Send this message in next Tx interval +Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders) + + + + + Ctrl+1 + + + + + + + + Switch to this Tx message NOW + + + + + Tx &2 + + + + + Alt+2 + + + + + <html><head/><body><p>Switch to this Tx message NOW</p><p>Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders)</p></body></html> + + + + + Switch to this Tx message NOW +Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders) + + + + + Tx &1 + + + + + Alt+1 + + + + + Ctrl+6 + + + + + <html><head/><body><p>Send this message in next Tx interval</p><p>Double-click to reset to the standard 73 message</p></body></html> + + + + + Send this message in next Tx interval +Double-click to reset to the standard 73 message + + + + + Ctrl+5 + + + + + Ctrl+3 + + + + + Tx &3 + + + + + Alt+3 + + + + + <html><head/><body><p>Send this message in next Tx interval</p><p>Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type 2 compound call holders)</p><p>RR73 messages should only be used when you are reasonably confident that no message repetitions will be required</p></body></html> + + + + + Send this message in next Tx interval +Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type 2 compound call holders) +RR73 messages should only be used when you are reasonably confident that no message repetitions will be required + + + + + Ctrl+4 + + + + + <html><head/><body><p>Switch to this Tx message NOW</p><p>Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type2 compound call holders)</p><p>RR73 messages should only be used when you are reasonably confident that no message repetitions will be required</p></body></html> + + + + + Switch to this Tx message NOW +Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type2 compound call holders) +RR73 messages should only be used when you are reasonably confident that no message repetitions will be required + + + + + Tx &4 + + + + + Alt+4 + + + + + <html><head/><body><p>Switch to this Tx message NOW</p><p>Double-click to reset to the standard 73 message</p></body></html> + + + + + Switch to this Tx message NOW +Double-click to reset to the standard 73 message + + + + + Tx &5 + + + + + Alt+5 + + + + + Now + + + + + Generate standard messages for minimal QSO + + + + + Generate Std Msgs + + + + + Tx &6 + + + + + Alt+6 + + + + + + Enter a free text message (maximum 13 characters) +or select a predefined macro from the dropdown list. +Press ENTER to add the current text to the predefined +list. The list can be maintained in Settings (F2). + + + + + Queue up the next Tx message + + + + + Next + + + + + 2 + + + + + Calling CQ + + + + + Generate a CQ message + + + + + + + CQ + + + + + Generate message with RRR + + + + + RRR + + + + + Generate message with report + + + + + dB + + + + + Answering CQ + + + + + Generate message for replying to a CQ + + + + + + Grid + + + + + Generate message with R+report + + + + + R+dB + + + + + Generate message with 73 + + + + + 73 + + + + + Send this standard (generated) message + + + + + Gen msg + + + + + Send this free-text message (max 13 characters) + + + + + Free msg + + + + + 3 + + + + + Max dB + + + + + CQ AF + + + + + CQ AN + + + + + CQ AS + + + + + CQ EU + + + + + CQ NA + + + + + CQ OC + + + + + CQ SA + + + + + CQ 0 + + + + + CQ 1 + + + + + CQ 2 + + + + + CQ 3 + + + + + CQ 4 + + + + + CQ 5 + + + + + CQ 6 + + + + + CQ 7 + + + + + CQ 8 + + + + + CQ 9 + + + + + Reset + + + + + N List + + + + + N Slots + + + + + + Random + + + + + Call + + + + + S/N (dB) + + + + + Distance + + + + + More CQs + + + + + Percentage of 2-minute sequences devoted to transmitting. + + + + + % + + + + + Tx Pct + + + + + Band Hopping + + + + + Choose bands and times of day for band-hopping. + + + + + Schedule ... + + + + + Upload decoded messages to WSPRnet.org. + + + + + Upload spots + + + + + <html><head/><body><p>6 digit locators cause 2 different mesages to be sent, the second contains the full locator but only a hashed callsign, other stations must have decoded the first once before they can decode your call in the second. Check this option to only send 4 digit locators if it will avoid the two message protocol.</p></body></html> + + + + + 6 digit locators cause 2 different mesages to be sent, the second contains the full locator but only a hashed callsign, other stations must have decoded the first once before they can decode your call in the second. Check this option to only send 4 digit locators if it will avoid the two message protocol. + + + + + Prefer type 1 messages + + + + + No own call decodes + + + + + Transmit during the next 2-minute sequence. + + + + + Tx Next + + + + + Set Tx power in dBm (dB above 1 mW) as part of your WSPR message. + + + + + File + + + + + View + + + + + Decode + + + + + Save + + + + + Help + + + + + Mode + + + + + Configurations + + + + + Tools + + + + + Exit + + + + + Configuration + + + + + F2 + + + + + About WSJT-X + + + + + Waterfall + + + + + Open + + + + + Ctrl+O + + + + + Open next in directory + + + + + Decode remaining files in directory + + + + + Shift+F6 + + + + + Delete all *.wav && *.c2 files in SaveDir + + + + + None + + + + + Save all + + + + + Online User Guide + + + + + Keyboard shortcuts + + + + + Special mouse commands + + + + + JT9 + + + + + Save decoded + + + + + Normal + + + + + Deep + + + + + Monitor OFF at startup + + + + + Erase ALL.TXT + + + + + Erase wsjtx_log.adi + + + + + Convert mode to RTTY for logging + + + + + Log dB reports to Comments + + + + + Prompt me to log QSO + + + + + Blank line between decoding periods + + + + + Clear DX Call and Grid after logging + + + + + Display distance in miles + + + + + Double-click on call sets Tx Enable + + + + + + F7 + + + + + Tx disabled after sending 73 + + + + + Runaway Tx watchdog + + + + + Allow multiple instances + + + + + Tx freq locked to Rx freq + + + + + JT65 + + + + + JT9+JT65 + + + + + Tx messages to Rx Frequency window + + + + + Gray1 + + + + + Show DXCC entity and worked B4 status + + + + + Astronomical data + + + + + List of Type 1 prefixes and suffixes + + + + + Settings... + + + + + Local User Guide + + + + + Open log directory + + + + + JT4 + + + + + Message averaging + + + + + Enable averaging + + + + + Enable deep search + + + + + WSPR + + + + + Echo Graph + + + + + F8 + + + + + Echo + + + + + EME Echo mode + + + + + ISCAT + + + + + Fast Graph + + + + + F9 + + + + + &Download Samples ... + + + + + <html><head/><body><p>Download sample audio files demonstrating the various modes.</p></body></html> + + + + + MSK144 + + + + + QRA64 + + + + + Release Notes + + + + + Enable AP for DX Call + + + + + FreqCal + + + + + Measure reference spectrum + + + + + Measure phase response + + + + + Erase reference spectrum + + + + + Execute frequency calibration cycle + + + + + Equalization tools ... + + + + + WSPR-LF + + + + + Experimental LF/MF mode + + + + + FT8 + + + + + + Enable AP + + + + + Solve for calibration parameters + + + + + Copyright notice + + + + + Shift+F1 + + + + + Fox log + + + + + FT8 DXpedition Mode User Guide + + + + + Reset Cabrillo log ... + + + + + Color highlighting scheme + + + + + Contest Log + + + + + Export Cabrillo log ... + + + + + Quick-Start Guide to WSJT-X 2.0 + + + + + Contest log + + + + + Erase WSPR hashtable + + + + + FT4 + + + + + Rig Control Error + + + + + Do you want to reconfigure the radio interface? + + + + + Error Scanning ADIF Log + + + + + Scanned ADIF log, %1 worked before records created + + + + + Error Loading LotW Users Data + + + + + Error Writing WAV File + + + + + Configurations... + + + + + Error Killing jt9.exe Process + + + + + KillByName return code: %1 + + + + + Error removing "%1" + + + + + Click OK to retry + + + + + + Improper mode + + + + + + File Open Error + + + + + + + + + Cannot open "%1" for append: %2 + + + + + Error saving c2 file + + + + + Error in Sound Input + + + + + Error in Sound Output + + + + + Change Operator + + + + + New operator: + + + + + Status File Error + + + + + + Cannot open "%1" for writing: %2 + + + + + Subprocess Error + + + + + Subprocess failed with exit code %1 + + + + + + Running: %1 +%2 + + + + + Subprocess error + + + + + Reference spectrum saved + + + + + Invalid data in fmt.all at line %1 + + + + + Good Calibration Solution + + + + + <pre>%1%L2 ±%L3 ppm +%4%L5 ±%L6 Hz + +%7%L8 +%9%L10 Hz</pre> + + + + + Delete Calibration Measurements + + + + + The "fmt.all" file will be renamed as "fmt.bak" + + + + + If you make fair use of any part of WSJT-X under terms of the GNU General Public License, you must display the following copyright notice prominently in your derivative work: + +"The algorithms, source code, look-and-feel of WSJT-X and related programs, and protocol specifications for the modes FSK441, FT8, JT4, JT6M, JT9, JT65, JTMS, QRA64, ISCAT, MSK144 are Copyright (C) 2001-2019 by one or more of the following authors: Joseph Taylor, K1JT; Bill Somerville, G4WJS; Steven Franke, K9AN; Nico Palermo, IV3NWV; Greg Beam, KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; Philip Karn, KA9Q; and other members of the WSJT Development Group." + + + + + No data read from disk. Wrong file format? + + + + + Confirm Delete + + + + + Are you sure you want to delete all *.wav and *.c2 files in "%1"? + + + + + Keyboard Shortcuts + + + + + Special Mouse Commands + + + + + No more files to open. + + + + + Please choose another Tx frequency. WSJT-X will not knowingly transmit another mode in the WSPR sub-band on 30m. + + + + + WSPR Guard Band + + + + + Please choose another dial frequency. WSJT-X will not operate in Fox mode in the standard FT8 sub-bands. + + + + + Fox Mode warning + + + + + Should you switch to ARRL Field Day mode? + + + + + Should you switch to RTTY contest mode? + + + + + + + + Add to CALL3.TXT + + + + + Please enter a valid grid locator + + + + + Cannot open "%1" for read/write: %2 + + + + + %1 +is already in CALL3.TXT, do you wish to replace it? + + + + + Warning: DX Call field is empty. + + + + + Log file error + + + + + Cannot open "%1" + + + + + Error sending log to N1MM + + + + + Write returned "%1" + + + + + + + Confirm Erase + + + + + Are you sure you want to erase file ALL.TXT? + + + + + + Confirm Reset + + + + + Are you sure you want to erase your contest log? + + + + + Doing this will remove all QSO records for the current contest. They will be kept in the ADIF log file but will not be available for export in your Cabrillo log. + + + + + Cabrillo Log saved + + + + + Are you sure you want to erase file wsjtx_log.adi? + + + + + Are you sure you want to erase the WSPR hashtable? + + + + + VHF features warning + + + + + Tune digital gain + + + + + Transmit digital gain + + + + + Prefixes + + + + + Network Error + + + + + Error: %1 +UDP server %2:%3 + + + + + File Error + + + + + Phase Training Disabled + + + + + Phase Training Enabled + + + + + + Log File Error + + + + + Are you sure you want to clear the QSO queues? + + + + + MessageAveraging + + + + Message Averaging + + + + + UTC Sync DT Freq + + + + + Modes + + + + Mode + + + + + MultiSettings + + + Default + + + + + MultiSettings::impl + + + &Switch To + + + + + &Clone + + + + + Clone &Into ... + + + + + R&eset + + + + + &Rename ... + + + + + &Delete + + + + + Clone Into Configuration + + + + + Confirm overwrite of all values for configuration "%1" with values from "%2"? + + + + + Reset Configuration + + + + + Confirm reset to default values for configuration "%1"? + + + + + Delete Configuration + + + + + Confirm deletion of configuration "%1"? + + + + + NameDialog + + + New Configuration Name + + + + + Old name: + + + + + &New name: + + + + + OmniRigTransceiver + + + OmniRig: unrecognized mode + + + + + Failed to start OmniRig COM server + + + + + + OmniRig: don't know how to set rig frequency + + + + + + OmniRig: timeout waiting for update from rig + + + + + OmniRig COM/OLE error: %1 at %2: %3 (%4) + + + + + PollingTransceiver + + + Unexpected rig error + + + + + QObject + + + Invalid rig name - \ & / not allowed + + + + + User Defined + + + + + Failed to open LotW users CSV file: '%1' + + + + + OOB + + + + + Too many colours in palette. + + + + + Error reading waterfall palette file "%1:%2" too many colors. + + + + + Error reading waterfall palette file "%1:%2" invalid triplet. + + + + + Error reading waterfall palette file "%1:%2" invalid color. + + + + + Error opening waterfall palette file "%1": %2. + + + + + Error writing waterfall palette file "%1": %2. + + + + + RemoteFile + + + + + + + + File System Error + + + + + Cannot rename file: +"%1" +to: "%2" +Error(%3): %4 + + + + + Cannot delete file: +"%1" + + + + + + + Network Error + + + + + Too many redirects: %1 + + + + + Redirect not followed: %1 + + + + + Cannot commit changes to: +"%1" + + + + + Cannot open file: +"%1" +Error(%2): %3 + + + + + Cannot make path: +"%1" + + + + + Cannot write to file: +"%1" +Error(%2): %3 + + + + + SampleDownloader::impl + + + Download Samples + + + + + Input Error + + + + + Invalid URL format + + + + + SoundInput + + + An error opening the audio input device has occurred. + + + + + An error occurred during read from the audio input device. + + + + + Audio data not being fed to the audio input device fast enough. + + + + + Non-recoverable error, audio input device not usable at this time. + + + + + Requested input audio format is not valid. + + + + + Requested input audio format is not supported on device. + + + + + Failed to initialize audio sink device + + + + + Idle + + + + + Receiving + + + + + Suspended + + + + + Interrupted + + + + + Error + + + + + Stopped + + + + + SoundOutput + + + An error opening the audio output device has occurred. + + + + + An error occurred during write to the audio output device. + + + + + Audio data not being fed to the audio output device fast enough. + + + + + Non-recoverable error, audio output device not usable at this time. + + + + + Requested output audio format is not valid. + + + + + Requested output audio format is not supported on device. + + + + + Idle + + + + + Sending + + + + + Suspended + + + + + Interrupted + + + + + Error + + + + + Stopped + + + + + StationDialog + + + Add Station + + + + + &Band: + + + + + &Offset (MHz): + + + + + &Antenna: + + + + + StationList::impl + + + Band name + + + + + Frequency offset + + + + + Antenna description + + + + + Band + + + + + Offset + + + + + Antenna Description + + + + + TransceiverBase + + + Unexpected rig error + + + + + WideGraph + + + Dialog + + + + + Controls + + + + + Spectrum gain + + + + + Palette + + + + + <html><head/><body><p>Enter definition for a new color palette.</p></body></html> + + + + + Adjust... + + + + + Waterfall gain + + + + + <html><head/><body><p>Set fractional size of spectrum in this window.</p></body></html> + + + + + % + + + + + Spec + + + + + <html><head/><body><p>Flatten spectral baseline over the full displayed interval.</p></body></html> + + + + + Flatten + + + + + <html><head/><body><p>Compute and save a reference spectrum. (Not yet fully implemented.)</p></body></html> + + + + + Ref Spec + + + + + Smoothing of Linear Average spectrum + + + + + Smooth + + + + + Compression factor for frequency scale + + + + + Bins/Pixel + + + + + Select waterfall palette + + + + + <html><head/><body><p>Select data for spectral display</p></body></html> + + + + + Current + + + + + Cumulative + + + + + Linear Avg + + + + + Reference + + + + + <html><head/><body><p>Frequency at left edge of waterfall</p></body></html> + + + + + Hz + + + + + Start + + + + + <html><head/><body><p>Decode JT9 only above this frequency</p></body></html> + + + + + JT9 + + + + + JT65 + + + + + Number of FFTs averaged (controls waterfall scrolling rate) + + + + + N Avg + + + + + Waterfall zero + + + + + Spectrum zero + + + + + Wide Graph + + + + + + Read Palette + + + + + configuration_dialog + + + Settings + + + + + Genera&l + + + + + General station details and settings. + + + + + Station Details + + + + + My C&all: + + + + + Station callsign. + + + + + M&y Grid: + + + + + <html><head/><body><p>Maidenhead locator, preferably 6 characters.</p></body></html> + + + + + Check to allow grid changes from external programs + + + + + AutoGrid + + + + + IARU Region: + + + + + <html><head/><body><p>Select your IARU region.</p></body></html> + + + + + Message generation for type 2 compound callsign holders: + + + + + <html><head/><body><p>Type 2 compound callsigns are those with prefixes or suffixes not included in the allowed shortlist (See Help-&gt;Add-on prefixes and suffixes).</p><p>This option determines which generated messages should contain your full type 2 compound call sign rather than your base callsign. It only applies if you have a type 2 compound callsign.</p><p>This option controls the way the messages that are used to answer CQ calls are generated. Generated messages 6 (CQ) and 5 (73) will always contain your full callsign. The JT65 and JT9 protocols allow for some standard messages with your full call at the expense of another piece of information such as the DX call or your locator.</p><p>Choosing message 1 omits the DX callsign which may be an issue when replying to CQ calls. Choosing message 3 also omits the DX callsign and many versions of this and other software will not extract the report. Choosing neither means that your full callsign only goes in your message 5 (73) so your QSO partner may log the wrong callsign.</p><p>None of these options are perfect, message 3 is usually best but be aware your QSO partner may not log the report you send them.</p></body></html> + + + + + Full call in Tx1 + + + + + Full call in Tx3 + + + + + Full call in Tx5 only + + + + + Display + + + + + Show outgoing transmitted messages in the Rx frequency window. + + + + + &Tx messages to Rx frequency window + + + + + Show if decoded stations are new DXCC entities or worked before. + + + + + Show &DXCC, grid, and worked-before status + + + + + <html><head/><body><p>Check to have decodes for a new period start at the top of the Band Activity window and not scroll off the top when the window is full.</p><p>This is to aid selecting decodes to double-click while decoding is still in progress. Use the Band Activity vertical scroll bar to reveal decodes past the bottom of the window.</p></body></html> + + + + + Start new period decodes at top + + + + + Show principal prefix instead of country name + + + + + Set the font characteristics for the application. + + + + + Font... + + + + + Set the font characteristics for the Band Activity and Rx Frequency areas. + + + + + Decoded Text Font... + + + + + Include a separator line between periods in the band activity window. + + + + + &Blank line between decoding periods + + + + + Show distance to DX station in miles rather than kilometers. + + + + + Display dista&nce in miles + + + + + Behavior + + + + + Decode after EME delay + + + + + Tx watchdog: + + + + + <html><head/><body><p>Number of minutes before unattended transmissions are aborted</p></body></html> + + + + + Disabled + + + + + minutes + + + + + Enable VHF/UHF/Microwave features + + + + + Single decode + + + + + <html><head/><body><p>Some rigs are not able to process CAT commands while transmitting. This means that if you are operating in split mode you may have to uncheck this option.</p></body></html> + + + + + Allow Tx frequency changes while transmitting + + + + + Don't start decoding until the monitor button is clicked. + + + + + Mon&itor off at startup + + + + + <html><head/><body><p>Check this if you wish to automatically return to the last monitored frequency when monitor is enabled, leave it unchecked if you wish to have the current rig frequency maintained.</p></body></html> + + + + + Monitor returns to last used frequency + + + + + Alternate F1-F6 bindings + + + + + Turns off automatic transmissions after sending a 73 or any other free +text message. + + + + + Di&sable Tx after sending 73 + + + + + Send a CW ID after every 73 or free text message. + + + + + CW ID a&fter 73 + + + + + Periodic CW ID Inter&val: + + + + + Send a CW ID periodically every few minutes. +This might be required under your countries licence regulations. +It will not interfere with other users as it is always sent in the +quiet period when decoding is done. + + + + + Automatic transmission mode. + + + + + Doubl&e-click on call sets Tx enable + + + + + Calling CQ forces Call 1st + + + + + &Radio + + + + + Radio interface configuration settings. + + + + + Settings that control your CAT interface. + + + + + CAT Control + + + + + + Port: + + + + + Serial port used for CAT control. + + + + + Serial Port Parameters + + + + + Baud Rate: + + + + + Serial port data rate which must match the setting of your radio. + + + + + 1200 + + + + + 2400 + + + + + 4800 + + + + + 9600 + + + + + 19200 + + + + + 38400 + + + + + 57600 + + + + + 115200 + + + + + <html><head/><body><p>Number of data bits used to communicate with your radio's CAT interface (usually eight).</p></body></html> + + + + + Data Bits + + + + + D&efault + + + + + Se&ven + + + + + E&ight + + + + + <html><head/><body><p>Number of stop bits used when communicating with your radio's CAT interface</p><p>(consult you radio's manual for details).</p></body></html> + + + + + Stop Bits + + + + + + Default + + + + + On&e + + + + + T&wo + + + + + <html><head/><body><p>Flow control protocol used between this computer and your radio's CAT interface (usually &quot;None&quot; but some require &quot;Hardware&quot;).</p></body></html> + + + + + Handshake + + + + + &None + + + + + Software flow control (very rare on CAT interfaces). + + + + + XON/XOFF + + + + + Flow control using the RTS and CTS RS-232 control lines +not often used but some radios have it as an option and +a few, particularly some Kenwood rigs, require it). + + + + + &Hardware + + + + + Special control of CAT port control lines. + + + + + Force Control Lines + + + + + + High + + + + + + Low + + + + + DTR: + + + + + RTS: + + + + + How this program activates the PTT on your radio + + + + + PTT Method + + + + + <html><head/><body><p>No PTT activation, instead the radio's automatic VOX is used to key the transmitter.</p><p>Use this if you have no radio interface hardware.</p></body></html> + + + + + VO&X + + + + + <html><head/><body><p>Use the RS-232 DTR control line to toggle your radio's PTT, requires hardware to inteface the line.</p><p>Some commercial interface units also use this method.</p><p>The DTR control line of the CAT serial port may be used for this or a DTR control line on a different serial port may be used.</p></body></html> + + + + + &DTR + + + + + Some radios support PTT via CAT commands, +use this option if your radio supports it and you have no +other hardware interface for PTT. + + + + + C&AT + + + + + <html><head/><body><p>Use the RS-232 RTS control line to toggle your radio's PTT, requires hardware to inteface the line.</p><p>Some commercial interface units also use this method.</p><p>The RTS control line of the CAT serial port may be used for this or a RTS control line on a different serial port may be used. Note that this option is not available on the CAT serial port when hardware flow control is used.</p></body></html> + + + + + R&TS + + + + + <html><head/><body><p>Select the RS-232 serial port utilised for PTT control, this option is available when DTR or RTS is selected above as a transmit method.</p><p>This port can be the same one as the one used for CAT control.</p><p>For some interface types the special value CAT may be chosen, this is used for non-serial CAT interfaces that can control serial port control lines remotely (OmniRig for example).</p></body></html> + + + + + Modulation mode selected on radio. + + + + + Mode + + + + + <html><head/><body><p>USB is usually the correct modulation mode,</p><p>unless the radio has a special data or packet mode setting</p><p>for AFSK operation.</p></body></html> + + + + + US&B + + + + + Don't allow the program to set the radio mode +(not recommended but use if the wrong mode +or bandwidth is selected). + + + + + + None + + + + + If this is availabe then it is usually the correct mode for this program. + + + + + Data/P&kt + + + + + Some radios can select the audio input using a CAT command, +this setting allows you to select which audio input will be used +(if it is available then generally the Rear/Data option is best). + + + + + Transmit Audio Source + + + + + Rear&/Data + + + + + &Front/Mic + + + + + Rig: + + + + + Poll Interval: + + + + + <html><head/><body><p>Interval to poll rig for status. Longer intervals will mean that changes to the rig will take longer to be detected.</p></body></html> + + + + + s + + + + + <html><head/><body><p>Attempt to connect to the radio with these settings.</p><p>The button will turn green if the connection is successful or red if there is a problem.</p></body></html> + + + + + Test CAT + + + + + Attempt to activate the transmitter. +Click again to deactivate. Normally no power should be +output since there is no audio being generated at this time. +Check that any Tx indication on your radio and/or your +radio interface behave as expected. + + + + + Test PTT + + + + + Split Operation + + + + + Fake It + + + + + Rig + + + + + A&udio + + + + + Audio interface settings + + + + + Souncard + + + + + Soundcard + + + + + 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. + + + + + Select the audio CODEC to use for receiving. + + + + + &Input: + + + + + Select the channel to use for receiving. + + + + + + Mono + + + + + + Left + + + + + + Right + + + + + + Both + + + + + Select the audio channel used for transmission. +Unless you have multiple radios connected on different +channels; then you will usually want to select mono or +both here. + + + + + Ou&tput: + + + + + + Save Directory + + + + + Loc&ation: + + + + + Path to which .WAV files are saved. + + + + + + TextLabel + + + + + Click to select a different save directory for .WAV files. + + + + + S&elect + + + + + + AzEl Directory + + + + + Location: + + + + + Select + + + + + Power Memory By Band + + + + + Remember power settings by band + + + + + Enable power memory during transmit + + + + + Transmit + + + + + Enable power memory during tuning + + + + + Tune + + + + + Tx &Macros + + + + + Canned free text messages setup + + + + + &Add + + + + + &Delete + + + + + Drag and drop items to rearrange order +Right click for item specific actions +Click, SHIFT+Click and, CRTL+Click to select items + + + + + Reportin&g + + + + + Reporting and logging settings + + + + + Logging + + + + + The program will pop up a partially completed Log QSO dialog when you send a 73 or free text message. + + + + + Promp&t me to log QSO + + + + + Op Call: + + + + + Some logging programs will not accept the type of reports +saved by this program. +Check this option to save the sent and received reports in the +comments field. + + + + + d&B reports to comments + + + + + Check this option to force the clearing of the DX Call +and DX Grid fields when a 73 or free text message is sent. + + + + + Clear &DX call and grid after logging + + + + + <html><head/><body><p>Some logging programs will not accept WSJT-X mode names.</p></body></html> + + + + + Con&vert mode to RTTY + + + + + <html><head/><body><p>The callsign of the operator, if different from the station callsign.</p></body></html> + + + + + <html><head/><body><p>Check to have QSOs logged automatically, when complete.</p></body></html> + + + + + Log automatically (contesting only) + + + + + Network Services + + + + + The program can send your station details and all +decoded signals as spots to the http://pskreporter.info web site. +This is used for reverse beacon analysis which is very useful +for assessing propagation and system performance. + + + + + Enable &PSK Reporter Spotting + + + + + UDP Server + + + + + UDP Server: + + + + + <html><head/><body><p>Optional hostname of network service to receive decodes.</p><p>Formats:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 multicast group address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 multicast group address</li></ul><p>Clearing this field will disable the broadcasting of UDP status updates.</p></body></html> + + + + + UDP Server port number: + + + + + <html><head/><body><p>Enter the service port number of the UDP server that WSJT-X should send updates to. If this is zero no updates will be broadcast.</p></body></html> + + + + + <html><head/><body><p>With this enabled WSJT-X will accept certain requests back from a UDP server that receives decode messages.</p></body></html> + + + + + Accept UDP requests + + + + + <html><head/><body><p>Indicate acceptance of an incoming UDP request. The effect of this option varies depending on the operating system and window manager, its intent is to notify the acceptance of an incoming UDP request even if this application is minimized or hidden.</p></body></html> + + + + + Notify on accepted UDP request + + + + + <html><head/><body><p>Restore the window from minimized if an UDP request is accepted.</p></body></html> + + + + + Accepted UDP request restores window + + + + + Secondary UDP Server (deprecated) + + + + + <html><head/><body><p>When checked, WSJT-X will broadcast a logged contact in ADIF format to the configured hostname and port. </p></body></html> + + + + + Enable logged contact ADIF broadcast + + + + + Server name or IP address: + + + + + <html><head/><body><p>Optional host name of N1MM Logger+ program to receive ADIF UDP broadcasts. This is usually 'localhost' or ip address 127.0.0.1</p><p>Formats:</p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv4 multicast group address</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IPv6 multicast group address</li></ul><p>Clearing this field will disable broadcasting of ADIF information via UDP.</p></body></html> + + + + + Server port number: + + + + + <html><head/><body><p>Enter the port number that WSJT-X should use for UDP broadcasts of ADIF log information. For N1MM Logger+, this value should be 2333. If this is zero, no updates will be broadcast.</p></body></html> + + + + + Frequencies + + + + + Default frequencies and band specific station details setup + + + + + <html><head/><body><p>See &quot;Frequency Calibration&quot; in the WSJT-X User Guide for details of how to determine these parameters for your radio.</p></body></html> + + + + + Frequency Calibration + + + + + Slope: + + + + + ppm + + + + + Intercept: + + + + + Hz + + + + + Working Frequencies + + + + + <html><head/><body><p>Right click to maintain the working frequencies list.</p></body></html> + + + + + Station Information + + + + + Items may be edited. +Right click for insert and delete options. + + + + + Colors + Cores + + + + Decode Highlightling + + + + + <html><head/><body><p>Enable or disable using the check boxes and right-click an item to change or unset the foreground color, background color, or reset the item to default values. Drag and drop the items to change their priority, higher in the list is higher in priority.</p><p>Note that each foreground or background color may be either set or unset, unset means that it is not allocated for that item's type and lower priority items may apply.</p></body></html> + + + + + <html><head/><body><p>Push to reset all highlight items above to default values and priorities.</p></body></html> + + + + + Reset Highlighting + + + + + <html><head/><body><p>Check to indicate new DXCC entities, grid squares, and callsigns per mode.</p></body></html> + + + + + Highlight by Mode + + + + + <html><head/><body><p>Click to scan the wsjtx_log.adi ADIF file again for worked before information</p></body></html> + + + + + Rescan ADIF Log + + + + + Include extra WAE entities + + + + + <html><head/><body><p>Controls for Logbook of the World user lookup.</p></body></html> + + + + + Logbook of the World User Validation + + + + + Users CSV file URL: + + + + + <html><head/><body><p>URL of the ARRL LotW user's last upload dates and times data file which is used to highlight decodes from stations that are known to upload their log file to LotW.</p></body></html> + + + + + https://lotw.arrl.org/lotw-user-activity.csv + + + + + <html><head/><body><p>Push this button to fetch the latest LotW user's upload date and time data file.</p></body></html> + + + + + Fetch Now + + + + + Age of last upload less than: + + + + + <html><head/><body><p>Adjust this spin box to set the age threshold of LotW user's last upload date that is accepted as a current LotW user.</p></body></html> + + + + + days + + + + + Advanced + + + + + <html><head/><body><p>User-selectable parameters for JT65 VHF/UHF/Microwave decoding.</p></body></html> + + + + + JT65 VHF/UHF/Microwave decoding parameters + + + + + Random erasure patterns: + + + + + <html><head/><body><p>Maximum number of erasure patterns for stochastic soft-decision Reed Solomon decoder is 10^(n/2).</p></body></html> + + + + + Aggressive decoding level: + + + + + <html><head/><body><p>Higher levels will increase the probability of decoding, but will also increase probability of a false decode.</p></body></html> + + + + + Two-pass decoding + + + + + Special operating activity: Generation of FT4, FT8, and MSK144 messages + + + + + <html><head/><body><p>FT8 DXpedition mode: Hound operator calling the DX.</p></body></html> + + + + + Hound + + + + + <html><head/><body><p>North American VHF/UHF/Microwave contests and others in which a 4-character grid locator is the required exchange.</p></body></html> + + + + + NA VHF Contest + + + + + <html><head/><body><p>FT8 DXpedition mode: Fox (DXpedition) operator.</p></body></html> + + + + + Fox + + + + + <html><head/><body><p>European VHF+ contests requiring a signal report, serial number, and 6-character locator.</p></body></html> + + + + + EU VHF Contest + + + + + + <html><head/><body><p>ARRL RTTY Roundup and similar contests. Exchange is US state, Canadian province, or &quot;DX&quot;.</p></body></html> + + + + + RTTY Roundup messages + + + + + RTTY RU Exch: + + + + + NJ + + + + + + <html><head/><body><p>ARRL Field Day exchange: number of transmitters, Class, and ARRL/RAC section or &quot;DX&quot;.</p></body></html> + + + + + ARRL Field Day + + + + + FD Exch: + + + + + 6A SNJ + + + + + Miscellaneous + + + + + Degrade S/N of .wav file: + + + + + + For offline sensitivity tests + + + + + dB + + + + + Receiver bandwidth: + + + + + Hz + + + + + Tx delay: + + + + + Minimum delay between assertion of PTT and start of Tx audio. + + + + + s + + + + + Tone spacing + + + + + <html><head/><body><p>Generate Tx audio with twice the normal tone spacing. Intended for special LF/MF transmitters that use a divide-by-2 before generating RF.</p></body></html> + + + + + x 2 + + + + + <html><head/><body><p>Generate Tx audio with four times the normal tone spacing. Intended for special LF/MF transmitters that use a divide-by-4 before generating RF.</p></body></html> + + + + + x 4 + + + + + Waterfall spectra + + + + + Low sidelobes + + + + + Most sensitive + + + + + <html><head/><body><p>Discard (Cancel) or apply (OK) configuration changes including</p><p>resetting the radio interface and applying any soundcard changes</p></body></html> + + + + + main + + + + Fatal error + + + + + + Unexpected fatal error + + + + + Where <rig-name> is for multi-instance support. + + + + + rig-name + + + + + Where <configuration> is an existing one. + + + + + configuration + + + + + Writable files in test location. Use with caution, for testing only. + + + + + Command line error + + + + + Command line help + + + + + Application version + + + + + Another instance may be running + + + + + try to remove stale lock file? + + + + + Failed to create a temporary directory + + + + + + Path: "%1" + + + + + Failed to create a usable temporary directory + + + + + Another application may be locking the directory + + + + + Failed to create data directory + + + + + path: "%1" + + + + + Shared memory error + + + + + Unable to create shared memory segment + + + + + wf_palette_design_dialog + + + Palette Designer + + + + + <html><head/><body><p>Double click a color to edit it.</p><p>Right click to insert or delete colors.</p><p>Colors at the top represent weak signals</p><p>and colors at the bottom represent strong</p><p>signals. You can have up to 256 colors.</p></body></html> + + + + diff --git a/validators/MaidenheadLocatorValidator.cpp b/validators/MaidenheadLocatorValidator.cpp index 9de41233e..e7e1134c7 100644 --- a/validators/MaidenheadLocatorValidator.cpp +++ b/validators/MaidenheadLocatorValidator.cpp @@ -64,7 +64,7 @@ auto MaidenheadLocatorValidator::validate (QString& input, int& pos) const -> St auto subsquare = match.captured ("subsquare"); if (subsquare.size ()) { - input.replace (match.capturedStart ("subsquare"), match.capturedLength ("subsquare"), subsquare.toLower ()); + input.replace (match.capturedStart ("subsquare"), match.capturedLength ("subsquare"), subsquare.toUpper ()); } if (match.hasMatch ()) return Acceptable; if (!input.size () || match.hasPartialMatch ()) return Intermediate; diff --git a/widgets/AbstractLogWindow.cpp b/widgets/AbstractLogWindow.cpp index efa1e60f1..bbe07a846 100644 --- a/widgets/AbstractLogWindow.cpp +++ b/widgets/AbstractLogWindow.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -16,7 +17,10 @@ #include "pimpl_impl.hpp" class AbstractLogWindow::impl final + : public QObject { + Q_OBJECT + public: impl (AbstractLogWindow * self, QString const& settings_key, QSettings * settings , Configuration const * configuration) @@ -38,6 +42,9 @@ public: FontOverrideModel model_; }; +#include "moc_AbstractLogWindow.cpp" +#include "AbstractLogWindow.moc" + namespace { bool row_is_higher (QModelIndex const& lhs, QModelIndex const& rhs) diff --git a/widgets/AbstractLogWindow.hpp b/widgets/AbstractLogWindow.hpp index 581212d82..476ff62f3 100644 --- a/widgets/AbstractLogWindow.hpp +++ b/widgets/AbstractLogWindow.hpp @@ -19,6 +19,8 @@ class QFont; class AbstractLogWindow : public QWidget { + Q_OBJECT + public: AbstractLogWindow (QString const& settings_key, QSettings * settings , Configuration const * configuration diff --git a/widgets/CabrilloLogWindow.cpp b/widgets/CabrilloLogWindow.cpp index 44a52cc6b..6fd753136 100644 --- a/widgets/CabrilloLogWindow.cpp +++ b/widgets/CabrilloLogWindow.cpp @@ -1,12 +1,13 @@ #include "CabrilloLogWindow.hpp" +#include #include #include #include #include "Configuration.hpp" #include "models/Bands.hpp" +#include "item_delegates/FrequencyDelegate.hpp" #include "item_delegates/ForeignKeyDelegate.hpp" -#include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp" #include "item_delegates/CallsignDelegate.hpp" #include "pimpl_impl.hpp" @@ -30,7 +31,7 @@ namespace switch (index.column ()) { case 1: - case 6: + case 7: return Qt::AlignRight + Qt::AlignVCenter; default: break; @@ -64,11 +65,10 @@ CabrilloLogWindow::CabrilloLogWindow (QSettings * settings, Configuration const m_->format_model_.setSourceModel (m_->log_model_); m_->ui_.log_table_view->setModel (&m_->format_model_); set_log_view (m_->ui_.log_table_view); - m_->ui_.log_table_view->setItemDelegateForColumn (2, new DateTimeAsSecsSinceEpochDelegate {this}); - m_->ui_.log_table_view->setItemDelegateForColumn (3, new CallsignDelegate {this}); - m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), 0, this}); + m_->ui_.log_table_view->setItemDelegateForColumn (1, new FrequencyDelegate {this}); + m_->ui_.log_table_view->setItemDelegateForColumn (4, new CallsignDelegate {this}); auto h_header = m_->ui_.log_table_view->horizontalHeader (); - h_header->moveSection (6, 1); // band to first column + h_header->moveSection (7, 1); // band to first column } CabrilloLogWindow::~CabrilloLogWindow () diff --git a/widgets/CabrilloLogWindow.ui b/widgets/CabrilloLogWindow.ui index efefe5d3c..35b4d597d 100644 --- a/widgets/CabrilloLogWindow.ui +++ b/widgets/CabrilloLogWindow.ui @@ -19,6 +19,9 @@ <html><head/><body><p>Right-click here for available actions.</p></body></html> + + Right-click here for available actions. + true diff --git a/widgets/DateTimeEdit.hpp b/widgets/DateTimeEdit.hpp new file mode 100644 index 000000000..ad767a551 --- /dev/null +++ b/widgets/DateTimeEdit.hpp @@ -0,0 +1,23 @@ +#ifndef DATE_TIME_EDIT_HPP_ +#define DATE_TIME_EDIT_HPP_ + +#include + +class QWidget; + +// +// DateTimeEdit - format includes seconds +// +class DateTimeEdit final + : public QDateTimeEdit +{ +public: + explicit DateTimeEdit (QWidget * parent = nullptr) + : QDateTimeEdit {parent} + { + setDisplayFormat (locale ().dateFormat (QLocale::ShortFormat) + " hh:mm:ss"); + setTimeSpec (Qt::UTC); + } +}; + +#endif diff --git a/widgets/DecodeHighlightingListView.cpp b/widgets/DecodeHighlightingListView.cpp index cc5ea5d2e..cfb14fc5d 100644 --- a/widgets/DecodeHighlightingListView.cpp +++ b/widgets/DecodeHighlightingListView.cpp @@ -6,6 +6,8 @@ #include "models/DecodeHighlightingModel.hpp" #include "MessageBox.hpp" +#include "moc_DecodeHighlightingListView.cpp" + DecodeHighlightingListView::DecodeHighlightingListView (QWidget * parent) : QListView {parent} { diff --git a/widgets/DecodeHighlightingListView.hpp b/widgets/DecodeHighlightingListView.hpp index 86aa86f4f..76fd507b7 100644 --- a/widgets/DecodeHighlightingListView.hpp +++ b/widgets/DecodeHighlightingListView.hpp @@ -16,6 +16,8 @@ class QWidget; class DecodeHighlightingListView final : public QListView { + Q_OBJECT + public: explicit DecodeHighlightingListView (QWidget * parent = nullptr); diff --git a/widgets/ExportCabrillo.cpp b/widgets/ExportCabrillo.cpp index 0e61f0f08..5fb54c7dc 100644 --- a/widgets/ExportCabrillo.cpp +++ b/widgets/ExportCabrillo.cpp @@ -11,6 +11,7 @@ #include "models/CabrilloLog.hpp" #include "ui_ExportCabrillo.h" +#include "moc_ExportCabrillo.cpp" ExportCabrillo::ExportCabrillo (QSettings * settings, Configuration const * configuration , CabrilloLog const * log, QWidget * parent) diff --git a/widgets/ExportCabrillo.h b/widgets/ExportCabrillo.h index fbc9294cd..0dfbf6754 100644 --- a/widgets/ExportCabrillo.h +++ b/widgets/ExportCabrillo.h @@ -15,6 +15,8 @@ namespace Ui { class ExportCabrillo final : public QDialog { + Q_OBJECT + public: explicit ExportCabrillo (QSettings *, Configuration const * , CabrilloLog const *, QWidget * parent = nullptr); diff --git a/widgets/FoxLogWindow.cpp b/widgets/FoxLogWindow.cpp index 36f20b85b..9c29a30ad 100644 --- a/widgets/FoxLogWindow.cpp +++ b/widgets/FoxLogWindow.cpp @@ -13,7 +13,6 @@ #include "models/Bands.hpp" #include "models/FoxLog.hpp" #include "item_delegates/ForeignKeyDelegate.hpp" -#include "item_delegates/DateTimeAsSecsSinceEpochDelegate.hpp" #include "item_delegates/CallsignDelegate.hpp" #include "item_delegates/MaidenheadLocatorDelegate.hpp" #include "pimpl_impl.hpp" @@ -42,7 +41,6 @@ FoxLogWindow::FoxLogWindow (QSettings * settings, Configuration const * configur m_->ui_.setupUi (this); m_->ui_.log_table_view->setModel (m_->log_->model ()); set_log_view (m_->ui_.log_table_view); - m_->ui_.log_table_view->setItemDelegateForColumn (1, new DateTimeAsSecsSinceEpochDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (2, new CallsignDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (3, new MaidenheadLocatorDelegate {this}); m_->ui_.log_table_view->setItemDelegateForColumn (6, new ForeignKeyDelegate {configuration->bands (), 0, this}); diff --git a/widgets/FrequencyDeltaLineEdit.cpp b/widgets/FrequencyDeltaLineEdit.cpp new file mode 100644 index 000000000..b7ed144b6 --- /dev/null +++ b/widgets/FrequencyDeltaLineEdit.cpp @@ -0,0 +1,54 @@ +#include "FrequencyDeltaLineEdit.hpp" + +#include + +#include +#include +#include + +#include "moc_FrequencyDeltaLineEdit.cpp" + +namespace +{ + class MHzValidator + : public QDoubleValidator + { + public: + MHzValidator (double bottom, double top, QObject * parent = nullptr) + : QDoubleValidator {bottom, top, 6, parent} + { + } + + State validate (QString& input, int& pos) const override + { + State result = QDoubleValidator::validate (input, pos); + if (Acceptable == result) + { + bool ok; + (void)QLocale {}.toDouble (input, &ok); + if (!ok) + { + result = Intermediate; + } + } + return result; + } + }; +} + +FrequencyDeltaLineEdit::FrequencyDeltaLineEdit (QWidget * parent) + : QLineEdit (parent) +{ + setValidator (new MHzValidator {-std::numeric_limits::max () / 10.e6, + std::numeric_limits::max () / 10.e6, this}); +} + +auto FrequencyDeltaLineEdit::frequency_delta () const -> FrequencyDelta +{ + return Radio::frequency_delta (text (), 6); +} + +void FrequencyDeltaLineEdit::frequency_delta (FrequencyDelta d) +{ + setText (Radio::frequency_MHz_string (d)); +} diff --git a/widgets/FrequencyDeltaLineEdit.hpp b/widgets/FrequencyDeltaLineEdit.hpp new file mode 100644 index 000000000..caa00ecba --- /dev/null +++ b/widgets/FrequencyDeltaLineEdit.hpp @@ -0,0 +1,29 @@ +#ifndef FREQUENCY_DELTA_LINE_EDIT_HPP_ +#define FREQUENCY_DELTA_LINE_EDIT_HPP_ + +#include + +#include "Radio.hpp" + +class QWidget; + +// +// MHz frequency delta line edit with validation +// +class FrequencyDeltaLineEdit final + : public QLineEdit +{ + Q_OBJECT; + Q_PROPERTY (FrequencyDelta frequency_delta READ frequency_delta WRITE frequency_delta USER true); + +public: + using FrequencyDelta = Radio::FrequencyDelta; + + explicit FrequencyDeltaLineEdit (QWidget * parent = nullptr); + + // Property frequency_delta implementation + FrequencyDelta frequency_delta () const; + void frequency_delta (FrequencyDelta); +}; + +#endif diff --git a/widgets/FrequencyLineEdit.cpp b/widgets/FrequencyLineEdit.cpp index 78f8b2e1f..1ca2ba20b 100644 --- a/widgets/FrequencyLineEdit.cpp +++ b/widgets/FrequencyLineEdit.cpp @@ -51,21 +51,3 @@ void FrequencyLineEdit::frequency (Frequency f) { setText (Radio::frequency_MHz_string (f)); } - - -FrequencyDeltaLineEdit::FrequencyDeltaLineEdit (QWidget * parent) - : QLineEdit (parent) -{ - setValidator (new MHzValidator {-std::numeric_limits::max () / 10.e6, - std::numeric_limits::max () / 10.e6, this}); -} - -auto FrequencyDeltaLineEdit::frequency_delta () const -> FrequencyDelta -{ - return Radio::frequency_delta (text (), 6); -} - -void FrequencyDeltaLineEdit::frequency_delta (FrequencyDelta d) -{ - setText (Radio::frequency_MHz_string (d)); -} diff --git a/widgets/FrequencyLineEdit.hpp b/widgets/FrequencyLineEdit.hpp index dec0feb00..7e535f5a9 100644 --- a/widgets/FrequencyLineEdit.hpp +++ b/widgets/FrequencyLineEdit.hpp @@ -8,7 +8,7 @@ class QWidget; // -// MHz frequency line edits with validation +// MHz frequency line edit with validation // class FrequencyLineEdit final : public QLineEdit @@ -26,20 +26,4 @@ public: void frequency (Frequency); }; -class FrequencyDeltaLineEdit final - : public QLineEdit -{ - Q_OBJECT; - Q_PROPERTY (FrequencyDelta frequency_delta READ frequency_delta WRITE frequency_delta USER true); - -public: - using FrequencyDelta = Radio::FrequencyDelta; - - explicit FrequencyDeltaLineEdit (QWidget * parent = nullptr); - - // Property frequency_delta implementation - FrequencyDelta frequency_delta () const; - void frequency_delta (FrequencyDelta); -}; - #endif diff --git a/widgets/HelpTextWindow.cpp b/widgets/HelpTextWindow.cpp index 98c2b38e3..d24a87a51 100644 --- a/widgets/HelpTextWindow.cpp +++ b/widgets/HelpTextWindow.cpp @@ -9,6 +9,8 @@ #include "qt_helpers.hpp" #include "widgets/MessageBox.hpp" +#include "moc_HelpTextWindow.cpp" + HelpTextWindow::HelpTextWindow (QString const& title, QString const& file_name, QFont const& font, QWidget * parent) : QLabel {parent, Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint} { diff --git a/widgets/HelpTextWindow.hpp b/widgets/HelpTextWindow.hpp index c5793ae97..5cc5a6dca 100644 --- a/widgets/HelpTextWindow.hpp +++ b/widgets/HelpTextWindow.hpp @@ -9,6 +9,8 @@ class QString; class HelpTextWindow final : public QLabel { + Q_OBJECT + public: HelpTextWindow (QString const& title, QString const& file_name, QFont const& = QFont {}, QWidget * parent = nullptr); }; diff --git a/widgets/RestrictedSpinBox.cpp b/widgets/RestrictedSpinBox.cpp index d3201b331..3d18ce488 100644 --- a/widgets/RestrictedSpinBox.cpp +++ b/widgets/RestrictedSpinBox.cpp @@ -17,3 +17,17 @@ QValidator::State RestrictedSpinBox::validate (QString& input, int& pos) const } return valid; } + +void RestrictedSpinBox::fixup (QString& input) const +{ + auto iter = std::lower_bound (values ().begin (), values ().end (), valueFromText (input)); + HintedSpinBox::fixup (input); + if (iter != values ().end ()) + { + input = textFromValue (*iter); + } + else + { + input = textFromValue (values ().back ()); + } +} diff --git a/widgets/RestrictedSpinBox.hpp b/widgets/RestrictedSpinBox.hpp index f856e90ce..e984c3770 100644 --- a/widgets/RestrictedSpinBox.hpp +++ b/widgets/RestrictedSpinBox.hpp @@ -20,6 +20,7 @@ public: protected: // override the base class validation QValidator::State validate (QString& input, int& pos) const override; + void fixup (QString& input) const override; }; #endif diff --git a/widgets/astro.cpp b/widgets/astro.cpp index 4ee55da4a..8c083a89a 100644 --- a/widgets/astro.cpp +++ b/widgets/astro.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "commons.h" #include "MessageBox.hpp" @@ -23,14 +24,14 @@ extern "C" { - void astrosub_(int* nyear, int* month, int* nday, double* uth, double* freqMoon, - const char* mygrid, const char* hisgrid, double* azsun, - double* elsun, double* azmoon, double* elmoon, double* azmoondx, - double* elmoondx, int* ntsky, int* ndop, int* ndop00, - double* ramoon, double* decmoon, double* dgrd, double* poloffset, - double* xnr, double* techo, double* width1, double* width2, - bool* bTx, const char* AzElFileName, const char* jpleph, - fortran_charlen_t, fortran_charlen_t, fortran_charlen_t, fortran_charlen_t); + void astrosub(int nyear, int month, int nday, double uth, double freqMoon, + const char * mygrid, size_t mygrid_len, const char * hisgrid, + size_t hisgrid_len, double * azsun, double * elsun, double * azmoon, + double * elmoon, double * azmoondx, double * elmoondx, int * ntsky, + int * ndop, int * ndop00, double * ramoon, double * decmoon, double * dgrd, + double * poloffset, double * xnr, double * techo, double * width1, + double * width2, bool bTx, const char * AzElFileName, size_t AzElFileName_len, + const char * jpleph, size_t jpleph_len); } Astro::Astro(QSettings * settings, Configuration const * configuration, QWidget * parent) @@ -75,8 +76,8 @@ void Astro::read_settings () case 1: ui_->rbFullTrack->setChecked (true); break; case 2: ui_->rbConstFreqOnMoon->setChecked (true); break; case 3: ui_->rbOwnEcho->setChecked (true); break; - case 4: ui_->rbOnDxEcho->setChecked (true); break; - case 5: ui_->rbCallDx->setChecked (true); break; + case 4: ui_->rbOnDxEcho->setChecked (true); break; + case 5: ui_->rbCallDx->setChecked (true); break; } move (settings_->value ("window/pos", pos ()).toPoint ()); } @@ -90,7 +91,7 @@ void Astro::write_settings () } auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const& hisgrid, Frequency freq, - bool dx_is_self, bool bTx, bool no_tx_QSY, int TR_period) -> Correction + bool dx_is_self, bool bTx, bool no_tx_QSY, double TR_period) -> Correction { Frequency freq_moon {freq}; double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx; @@ -106,24 +107,20 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const double sec {t.time().second() + 0.001*t.time().msec()}; double uth {nhr + nmin/60.0 + sec/3600.0}; if(freq_moon < 1) freq_moon = 144000000; - int nfreq {static_cast (freq_moon / 1000000u)}; - double freq8 {static_cast (freq_moon)}; auto const& AzElFileName = QDir::toNativeSeparators (configuration_->azel_directory ().absoluteFilePath ("azel.dat")); auto const& jpleph = configuration_->data_dir ().absoluteFilePath ("JPLEPH"); - - - - QString mygrid_padded {(mygrid + " ").left (6)}; - QString hisgrid_padded {(hisgrid + " ").left (6)}; - astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid_padded.toLatin1().constData(), - hisgrid_padded.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon, - &azmoondx, &elmoondx, &ntsky, &m_dop, &m_dop00, &ramoon, &decmoon, - &dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx, - AzElFileName.toLatin1().constData(), jpleph.toLatin1().constData(), 6, 6, - AzElFileName.length(), jpleph.length()); + astrosub(nyear, month, nday, uth, static_cast (freq_moon), + mygrid.toLatin1 ().constData (), mygrid.size (), + hisgrid.toLatin1().constData(), hisgrid.size (), + &azsun, &elsun, &azmoon, &elmoon, + &azmoondx, &elmoondx, &ntsky, &m_dop, &m_dop00, &ramoon, &decmoon, + &dgrd, &poloffset, &xnr, &techo, &width1, &width2, + bTx, + AzElFileName.toLatin1().constData(), AzElFileName.size (), + jpleph.toLatin1().constData(), jpleph.size ()); - if(hisgrid_padded==" ") { + if(!hisgrid.size ()) { azmoondx=0.0; elmoondx=0.0; m_dop=0; @@ -151,8 +148,8 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const "Dec: " << decmoon << "\n" "SunAz: " << azsun << "\n" "SunEl: " << elsun << "\n" - "Freq: " << nfreq << "\n"; - if(nfreq>=50) { //Suppress data not relevant below VHF + "Freq: " << freq / 1.e6 << "\n"; + if(freq>=5000000ull) { //Suppress data not relevant below VHF out << "Tsky: " << ntsky << "\n" "Dpol: " << poloffset << "\n" "MNR: " << xnr << "\n" @@ -211,11 +208,9 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const // // use a base time of (secs-since-epoch + 2) so as to be sure // we do the next period if we calculate just before it starts - auto sec_since_epoch = t.toMSecsSinceEpoch () / 1000 + 2; - auto target_sec = sec_since_epoch - sec_since_epoch % TR_period + TR_period / 2; + auto sec_since_epoch = t.toMSecsSinceEpoch ()/1000 + 2; + auto target_sec = sec_since_epoch - fmod(double(sec_since_epoch),TR_period) + 0.5*TR_period; auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, Qt::UTC); - QString date {target_date_time.date().toString("yyyy MMM dd").trimmed ()}; - QString utc {target_date_time.time().toString().trimmed ()}; int nyear {target_date_time.date().year()}; int month {target_date_time.date().month()}; int nday {target_date_time.date().day()}; @@ -223,12 +218,15 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const int nmin {target_date_time.time().minute()}; double sec {target_date_time.time().second() + 0.001*target_date_time.time().msec()}; double uth {nhr + nmin/60.0 + sec/3600.0}; - astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid_padded.toLatin1().constData(), - hisgrid_padded.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon, + astrosub(nyear, month, nday, uth, static_cast (freq_moon), + mygrid.toLatin1 ().constData (), mygrid.size (), + hisgrid.toLatin1().constData(), hisgrid.size (), + &azsun, &elsun, &azmoon, &elmoon, &azmoondx, &elmoondx, &ntsky, &m_dop, &m_dop00, &ramoon, &decmoon, - &dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx, - "", jpleph.toLatin1().constData(), 6, 6, - 0, jpleph.length()); + &dgrd, &poloffset, &xnr, &techo, &width1, &width2, + bTx, + AzElFileName.toLatin1().constData(), AzElFileName.size (), + jpleph.toLatin1().constData(), jpleph.size ()); FrequencyDelta offset {0}; switch (m_DopplerMethod) { @@ -254,7 +252,7 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const } correction.tx = -offset; - qDebug () << "correction.tx (no tx qsy):" << correction.tx; + qDebug () << "correction.tx (no tx qsy):" << correction.tx; } } return correction; diff --git a/widgets/astro.h b/widgets/astro.h index 03d8c66c6..4f7f71d5b 100644 --- a/widgets/astro.h +++ b/widgets/astro.h @@ -44,7 +44,7 @@ public: bool dx_is_self, bool bTx, bool no_tx_QSY, - int TR_period); + double TR_period); bool doppler_tracking () const; Q_SLOT void nominal_frequency (Frequency rx, Frequency tx); diff --git a/widgets/displaytext.cpp b/widgets/displaytext.cpp index ca3372f48..53d7cd5cd 100644 --- a/widgets/displaytext.cpp +++ b/widgets/displaytext.cpp @@ -271,7 +271,7 @@ QString DisplayText::appendWorkedB4 (QString message, QString call, QString cons if(call.length()<3) return message; if(!call.contains(QRegExp("[0-9]|[A-Z]"))) return message; - auto const& looked_up = logBook.countries ().lookup (call); + auto const& looked_up = logBook.countries ()->lookup (call); logBook.match (call, currentMode, grid, looked_up, callB4, countryB4, gridB4, continentB4, CQZoneB4, ITUZoneB4); logBook.match (call, currentMode, grid, looked_up, callB4onBand, countryB4onBand, gridB4onBand, continentB4onBand, CQZoneB4onBand, ITUZoneB4onBand, currentBand); @@ -374,6 +374,7 @@ QString DisplayText::appendWorkedB4 (QString message, QString call, QString cons appendage += countryName; } } + m_CQPriority=DecodeHighlightingModel::highlight_name(top_highlight); // use a nbsp to save the start of appended text so we can find // it again later, align appended data at a fixed column if @@ -423,6 +424,7 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con QRegularExpression grid_regexp {"\\A(?![Rr]{2}73)[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}\\z"}; if(!dxGrid.contains(grid_regexp)) dxGrid=""; message = message.left (message.indexOf (QChar::Nbsp)); // strip appended info + m_CQPriority=""; if (CQcall) { if (displayDXCCEntity) @@ -447,6 +449,7 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con set_colours (m_config, &bg, &fg, types); } } + appendText (message.trimmed (), bg, fg, decodedText.call (), dxCall); } @@ -454,6 +457,7 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,bool bFastMode) { QString t1=" @ "; + if(modeTx=="FT4") t1=" + "; if(modeTx=="FT8") t1=" ~ "; if(modeTx=="JT4") t1=" $ "; if(modeTx=="JT65") t1=" # "; @@ -461,7 +465,7 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx QString t2; t2.sprintf("%4d",txFreq); QString t; - if(bFastMode or modeTx=="FT8") { + if(bFastMode or modeTx=="FT8" or modeTx=="FT4") { t = QDateTime::currentDateTimeUtc().toString("hhmmss") + \ " Tx " + t2 + t1 + text; } else if(modeTx.mid(0,6)=="FT8fox") { diff --git a/widgets/displaytext.h b/widgets/displaytext.h index cd3426af9..8b580b8a2 100644 --- a/widgets/displaytext.h +++ b/widgets/displaytext.h @@ -35,6 +35,7 @@ public: void displayQSY(QString text); void displayFoxToBeCalled(QString t, QColor bg = QColor {}, QColor fg = QColor {}); void new_period (); + QString CQPriority(){return m_CQPriority;}; Q_SIGNAL void selectCallsign (Qt::KeyboardModifiers); Q_SIGNAL void erased (); @@ -51,6 +52,7 @@ private: Configuration const * m_config; bool m_bPrincipalPrefix; + QString m_CQPriority; QString appendWorkedB4(QString message, QString callsign , QString const& grid, QColor * bg, QColor * fg , LogBook const& logBook, QString const& currentBand @@ -63,6 +65,4 @@ private: int modified_vertical_scrollbar_max_; }; - extern QHash m_LoTW; - #endif // DISPLAYTEXT_H diff --git a/widgets/fastgraph.cpp b/widgets/fastgraph.cpp index e599138f2..9efe5fc63 100644 --- a/widgets/fastgraph.cpp +++ b/widgets/fastgraph.cpp @@ -86,9 +86,9 @@ void FastGraph::on_greenZeroSlider_valueChanged(int value) ui->fastPlot->draw(); } -void FastGraph::setTRPeriod(int n) +void FastGraph::setTRPeriod(double p) { - m_TRperiod=n; + m_TRperiod=p; ui->fastPlot->setTRperiod(m_TRperiod); } diff --git a/widgets/fastgraph.h b/widgets/fastgraph.h index 7ed32671f..b5f7c0b8d 100644 --- a/widgets/fastgraph.h +++ b/widgets/fastgraph.h @@ -22,7 +22,7 @@ public: void plotSpec(bool diskData, int UTCdisk); void saveSettings(); - void setTRPeriod(int n); + void setTRPeriod(double p); void setMode(QString mode); signals: @@ -40,8 +40,8 @@ protected: private: QSettings * m_settings; - float m_ave; - qint32 m_TRperiod; + float m_ave; + double m_TRperiod; QScopedPointer ui; }; diff --git a/widgets/fastplot.cpp b/widgets/fastplot.cpp index 1437834d8..a388f0ac7 100644 --- a/widgets/fastplot.cpp +++ b/widgets/fastplot.cpp @@ -135,11 +135,11 @@ void FPlotter::setGreenZero(int n) m_bPaint2=true; } -void FPlotter::setTRperiod(int n) +void FPlotter::setTRperiod(double p) { - m_TRperiod=n; + m_TRperiod=p; m_pixPerSecond=12000.0/512.0; - if(m_TRperiod<30) m_pixPerSecond=12000.0/256.0; + if(m_TRperiod<30.0) m_pixPerSecond=12000.0/256.0; drawScale(); update(); } diff --git a/widgets/fastplot.h b/widgets/fastplot.h index b13913388..f24fcc24e 100644 --- a/widgets/fastplot.h +++ b/widgets/fastplot.h @@ -37,7 +37,7 @@ public: void setPlotZero(int plotZero); void setPlotGain(int plotGain); void setGreenZero(int n); - void setTRperiod(int n); + void setTRperiod(double p); void drawScale(); void setMode(QString mode); @@ -68,6 +68,7 @@ private: QString m_mode; double m_pixPerSecond; + double m_TRperiod; qint32 m_hdivs; qint32 m_h; @@ -75,7 +76,6 @@ private: qint32 m_h2; QPixmap m_HorizPixmap; qint32 m_jh0; - qint32 m_TRperiod; bool m_bPaint2; }; diff --git a/widgets/logqso.cpp b/widgets/logqso.cpp index acbb340bc..14c92358b 100644 --- a/widgets/logqso.cpp +++ b/widgets/logqso.cpp @@ -16,11 +16,12 @@ #include "moc_logqso.cpp" LogQSO::LogQSO(QString const& programTitle, QSettings * settings - , Configuration const * config, QWidget *parent) + , Configuration const * config, LogBook * log, QWidget *parent) : QDialog {parent, Qt::WindowStaysOnTopHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint} , ui(new Ui::LogQSO) , m_settings (settings) , m_config {config} + , m_log {log} { ui->setupUi(this); setWindowTitle(programTitle + " - Log QSO"); @@ -57,8 +58,7 @@ void LogQSO::storeSettings () const void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, - Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd, - CabrilloLog * cabrillo_log) + Radio::Frequency dialFreq, bool noSuffix, QString xSent, QString xRcvd) { if(!isHidden()) return; ui->call->setText (hisCall); @@ -100,7 +100,6 @@ void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString ui->loggedOperator->setText(m_config->opCall()); ui->exchSent->setText (xSent); ui->exchRcvd->setText (xRcvd); - m_cabrilloLog = cabrillo_log; using SpOp = Configuration::SpecialOperatingActivity; auto special_op = m_config->special_op_id (); @@ -158,7 +157,7 @@ void LogQSO::accept() return; // without accepting } - if (!m_cabrilloLog->add_QSO (m_dialFreq, dateTimeOff, hisCall, xsent, xrcvd)) + if (!m_log->contest_log ()->add_QSO (m_dialFreq, mode, dateTimeOff, hisCall, xsent, xrcvd)) { show (); MessageBox::warning_message (this, tr ("Invalid QSO Data"), @@ -203,23 +202,23 @@ void LogQSO::accept() , m_myGrid , xsent , xrcvd - , LogBook::QSOToADIF (hisCall - , hisGrid - , mode - , rptSent - , rptRcvd - , dateTimeOn - , dateTimeOff - , band - , m_comments - , name - , strDialFreq - , m_myCall - , m_myGrid - , m_txPower - , operator_call - , xsent - , xrcvd)); + , m_log->QSOToADIF (hisCall + , hisGrid + , mode + , rptSent + , rptRcvd + , dateTimeOn + , dateTimeOff + , band + , m_comments + , name + , strDialFreq + , m_myCall + , m_myGrid + , m_txPower + , operator_call + , xsent + , xrcvd)); QDialog::accept(); } diff --git a/widgets/logqso.h b/widgets/logqso.h index 82a75b7bd..739a601f7 100644 --- a/widgets/logqso.h +++ b/widgets/logqso.h @@ -17,19 +17,19 @@ namespace Ui { class QSettings; class Configuration; class QByteArray; -class CabrilloLog; +class LogBook; class LogQSO : public QDialog { Q_OBJECT public: - explicit LogQSO(QString const& programTitle, QSettings *, Configuration const *, QWidget *parent = 0); + explicit LogQSO(QString const& programTitle, QSettings *, Configuration const *, LogBook *, QWidget *parent = 0); ~LogQSO(); void initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, Radio::Frequency dialFreq, - bool noSuffix, QString xSent, QString xRcvd, CabrilloLog *); + bool noSuffix, QString xSent, QString xRcvd); public slots: void accept(); @@ -54,12 +54,12 @@ private: QScopedPointer ui; QSettings * m_settings; Configuration const * m_config; + LogBook * m_log; QString m_txPower; QString m_comments; Radio::Frequency m_dialFreq; QString m_myCall; QString m_myGrid; - CabrilloLog * m_cabrilloLog; }; #endif // LogQSO_H diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 02818ec53..ec591ff86 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ #include #include #include +#include #include "revision_utils.hpp" #include "qt_helpers.hpp" @@ -86,8 +88,8 @@ extern "C" { //----------------------------------------------------- C and Fortran routines void symspec_(struct dec_data *, int* k, int* ntrperiod, int* nsps, int* ingain, - int* minw, float* px, float s[], float* df3, int* nhsym, int* npts8, - float *m_pxmax); + bool* bLowSidelobes, int* minw, float* px, float s[], float* df3, + int* nhsym, int* npts8, float *m_pxmax); void hspec_(short int d2[], int* k, int* nutc0, int* ntrperiod, int* nrxfreq, int* ntol, int* nContest, bool* bmsk144, bool* btrain, double const pcoeffs[], int* ingain, @@ -99,6 +101,15 @@ extern "C" { void genft8_(char* msg, int* i3, int* n3, char* msgsent, char ft8msgbits[], int itone[], fortran_charlen_t, fortran_charlen_t); + void genft4_(char* msg, int* ichk, char* msgsent, char ft4msgbits[], int itone[], + fortran_charlen_t, fortran_charlen_t); + + void gen_ft8wave_(int itone[], int* nsym, int* nsps, float* bt, float* fsample, float* f0, + float xjunk[], float wave[], int* icmplx, int* nwave); + + void gen_ft4wave_(int itone[], int* nsym, int* nsps, float* fsample, float* f0, + float xjunk[], float wave[], int* icmplx, int* nwave); + void gen4_(char* msg, int* ichk, char* msgsent, int itone[], int* itext, fortran_charlen_t, fortran_charlen_t); @@ -136,7 +147,7 @@ extern "C" { float* level, float* sigdb, float* snr, float* dfreq, float* width); - void fast_decode_(short id2[], int narg[], int* ntrperiod, + void fast_decode_(short id2[], int narg[], double * trperiod, char msg[], char mycall[], char hiscall[], fortran_charlen_t, fortran_charlen_t, fortran_charlen_t); void degrade_snr_(short d2[], int* n, float* db, float* bandwidth); @@ -159,6 +170,9 @@ extern "C" { void plotsave_(float swide[], int* m_w , int* m_h1, int* irow); void chkcall_(char* w, char* basc_call, bool cok, int len1, int len2); + + void get_ft4msg_(int* idecode, char* line, int len); + } int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols @@ -188,6 +202,7 @@ namespace QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>;]*"}; // grid exact match excluding RR73 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::max (); bool message_is_73 (int type, QStringList const& msg_parts) { @@ -221,8 +236,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_configurations_button {0}, m_settings {multi_settings->settings ()}, ui(new Ui::MainWindow), - m_logBook {&m_config}, m_config {&m_network_manager, temp_directory, m_settings, &m_logBook, this}, + m_logBook {&m_config}, m_WSPR_band_hopping {m_settings, &m_config, this}, m_WSPR_tx_next {false}, m_rigErrorMessageBox {MessageBox::Critical, tr ("Rig Control Error") @@ -231,10 +246,10 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_echoGraph (new EchoGraph(m_settings)), m_fastGraph (new FastGraph(m_settings)), // no parent so that it has a taskbar icon - m_logDlg (new LogQSO (program_title (), m_settings, &m_config, nullptr)), + m_logDlg (new LogQSO (program_title (), m_settings, &m_config, &m_logBook, nullptr)), m_lastDialFreq {0}, m_dialFreqRxWSPR {0}, - m_detector {new Detector {RX_SAMPLE_RATE, NTMAX, downSampleFactor}}, + m_detector {new Detector {RX_SAMPLE_RATE, double(NTMAX), downSampleFactor}}, m_FFTSize {6192 / 2}, // conservative value to avoid buffer overruns m_soundInput {new SoundInput}, m_modulator {new Modulator {TX_SAMPLE_RATE, NTMAX}}, @@ -245,6 +260,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_freqTxNominal {0}, m_s6 {0.}, m_tRemaining {0.}, + m_TRperiod {60.0}, m_DTtol {3.0}, m_waterfallAvg {1}, m_ntx {1}, @@ -256,7 +272,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_nutc0 {999999}, m_ntr {0}, m_tx {0}, - m_TRperiod {60}, m_inGain {0}, m_secID {0}, m_idleMinutes {0}, @@ -397,9 +412,11 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_config.udp_server_name (), m_config.udp_server_port (), this}}, psk_Reporter {new PSK_Reporter {m_messageClient, this}}, - m_manual {&m_network_manager} + m_manual {&m_network_manager}, + m_block_udp_status_updates {false} { ui->setupUi(this); + setUnifiedTitleAndToolBarOnMac (true); createStatusBar(); add_child_to_event_filter (this); ui->dxGridEntry->setValidator (new MaidenheadLocatorValidator {this}); @@ -487,6 +504,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, }); // Network message handlers + m_messageClient->enable (m_config.accept_udp_requests ()); connect (m_messageClient, &MessageClient::clear_decodes, [this] (quint8 window) { ++window; if (window & 1) @@ -499,52 +517,51 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, } }); connect (m_messageClient, &MessageClient::reply, this, &MainWindow::replyToCQ); + connect (m_messageClient, &MessageClient::close, this, &MainWindow::close); connect (m_messageClient, &MessageClient::replay, this, &MainWindow::replayDecodes); connect (m_messageClient, &MessageClient::location, this, &MainWindow::locationChange); connect (m_messageClient, &MessageClient::halt_tx, [this] (bool auto_only) { - if (m_config.accept_udp_requests ()) { - if (auto_only) { - if (ui->autoButton->isChecked ()) { - ui->autoButton->click(); - } - } else { - ui->stopTxButton->click(); + if (auto_only) { + if (ui->autoButton->isChecked ()) { + ui->autoButton->click(); } + } else { + ui->stopTxButton->click(); } }); connect (m_messageClient, &MessageClient::error, this, &MainWindow::networkError); connect (m_messageClient, &MessageClient::free_text, [this] (QString const& text, bool send) { - if (m_config.accept_udp_requests ()) { - tx_watchdog (false); - // send + non-empty text means set and send the free text - // message, !send + non-empty text means set the current free - // text message, send + empty text means send the current free - // text message without change, !send + empty text means clear - // the current free text message - if (0 == ui->tabWidget->currentIndex ()) { - if (!text.isEmpty ()) { - ui->tx5->setCurrentText (text); - } - if (send) { - ui->txb5->click (); - } else if (text.isEmpty ()) { - ui->tx5->setCurrentText (text); - } - } else if (1 == ui->tabWidget->currentIndex ()) { - if (!text.isEmpty ()) { - ui->freeTextMsg->setCurrentText (text); - } - if (send) { - ui->rbFreeText->click (); - } else if (text.isEmpty ()) { - ui->freeTextMsg->setCurrentText (text); - } + tx_watchdog (false); + // send + non-empty text means set and send the free text + // message, !send + non-empty text means set the current free + // text message, send + empty text means send the current free + // text message without change, !send + empty text means clear + // the current free text message + if (0 == ui->tabWidget->currentIndex ()) { + if (!text.isEmpty ()) { + ui->tx5->setCurrentText (text); + } + if (send) { + ui->txb5->click (); + } else if (text.isEmpty ()) { + ui->tx5->setCurrentText (text); + } + } else if (1 == ui->tabWidget->currentIndex ()) { + if (!text.isEmpty ()) { + ui->freeTextMsg->setCurrentText (text); + } + if (send) { + ui->rbFreeText->click (); + } else if (text.isEmpty ()) { + ui->freeTextMsg->setCurrentText (text); } - QApplication::alert (this); } + QApplication::alert (this); }); connect (m_messageClient, &MessageClient::highlight_callsign, ui->decodedTextBrowser, &DisplayText::highlight_callsign); + connect (m_messageClient, &MessageClient::switch_configuration, m_multi_settings, &MultiSettings::select_configuration); + connect (m_messageClient, &MessageClient::configure, this, &MainWindow::remote_configure); // Hook up WSPR band hopping connect (ui->band_hopping_schedule_push_button, &QPushButton::clicked @@ -555,6 +572,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, on_EraseButton_clicked (); QActionGroup* modeGroup = new QActionGroup(this); + ui->actionFT4->setActionGroup(modeGroup); ui->actionFT8->setActionGroup(modeGroup); ui->actionJT9->setActionGroup(modeGroup); ui->actionJT65->setActionGroup(modeGroup); @@ -694,6 +712,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, connect (&m_config, &Configuration::transceiver_failure, this, &MainWindow::handle_transceiver_failure); connect (&m_config, &Configuration::udp_server_changed, m_messageClient, &MessageClient::set_server); connect (&m_config, &Configuration::udp_server_port_changed, m_messageClient, &MessageClient::set_server_port); + connect (&m_config, &Configuration::accept_udp_requests_changed, m_messageClient, &MessageClient::enable); // set up configurations menu connect (m_multi_settings, &MultiSettings::configurationNameChanged, [this] (QString const& name) { @@ -704,6 +723,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, else { config_label.hide (); } + statusUpdate (); }); m_multi_settings->create_menu_actions (this, ui->menuConfig); m_configurations_button = m_rigErrorMessageBox.addButton (tr ("Configurations...") @@ -783,6 +803,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->TxPowerComboBox->addItem(t); } + m_dateTimeRcvdRR73=QDateTime::currentDateTimeUtc(); + m_dateTimeSentTx3=QDateTime::currentDateTimeUtc(); + ui->labAz->setStyleSheet("border: 0px;"); ui->labAz->setText(""); auto t = "UTC dB DT Freq Message"; @@ -861,7 +884,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, connect (&m_wav_future_watcher, &QFutureWatcher::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 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); Q_EMIT transmitFrequency (ui->TxFreqSpinBox->value () - m_XIT); @@ -885,19 +907,8 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, if(m_bFast9) m_bFastMode=true; ui->cbFast9->setChecked(m_bFast9 or m_bFastMode); - if(m_mode=="FT8") on_actionFT8_triggered(); - if(m_mode=="JT4") on_actionJT4_triggered(); - if(m_mode=="JT9") on_actionJT9_triggered(); - if(m_mode=="JT65") on_actionJT65_triggered(); - if(m_mode=="JT9+JT65") on_actionJT9_JT65_triggered(); - if(m_mode=="WSPR") on_actionWSPR_triggered(); - if(m_mode=="WSPR-LF") on_actionWSPR_LF_triggered(); - if(m_mode=="ISCAT") on_actionISCAT_triggered(); - if(m_mode=="MSK144") on_actionMSK144_triggered(); - if(m_mode=="QRA64") on_actionQRA64_triggered(); - if(m_mode=="Echo") on_actionEcho_triggered(); + set_mode (m_mode); if(m_mode=="Echo") monitor(false); //Don't auto-start Monitor in Echo mode. - if(m_mode=="FreqCal") on_actionFreqCal_triggered(); ui->sbSubmode->setValue (vhf ? m_nSubMode : 0); if(m_mode=="MSK144") { @@ -957,8 +968,12 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, splashTimer.setSingleShot (true); splashTimer.start (20 * 1000); - //QTimer::singleShot (0, this, SLOT (not_GA_warning_message ())); + if(QCoreApplication::applicationVersion().contains("-devel") or + QCoreApplication::applicationVersion().contains("-rc")) { + QTimer::singleShot (0, this, SLOT (not_GA_warning_message ())); + } + ui->pbBestSP->setVisible(m_mode=="FT4"); if(!ui->cbMenus->isChecked()) { ui->cbMenus->setChecked(true); ui->cbMenus->setChecked(false); @@ -971,18 +986,18 @@ void MainWindow::not_GA_warning_message () { MessageBox::critical_message (this, "

" - "IMPORTANT: New protocols for the FT8 and MSK144 modes " - "became the world‑wide standards on December 10, 2018." - , "

" - "WSJT‑X 2.0 cannot communicate in these modes with other " - "stations using WSJT‑X v1.9.1 or earlier." - "

" - "Please help by urging everyone to upgrade to WSJT‑X 2.0 " - "no later than January 1, 2019."); - -// QDateTime now=QDateTime::currentDateTime(); -// QDateTime timeout=QDateTime(QDate(2018,12,31)); -// if(now.daysTo(timeout) < 0) Q_EMIT finished(); + "This is a pre-release version of WSJT-X 2.1.0 made " + "available for testing purposes. By design it will " + "be nonfunctional during the 2019 ARRL June VHF contest " + "(June 8-10) and Field Day (June 22-23) weekends. It " + "will be permanently nonfunctional after July 21, 2019."); + auto now = QDateTime::currentDateTimeUtc (); + if ((QDateTime {{2019, 6, 8}, {18, 0}, Qt::UTC} <= now + && now < QDateTime {{2019, 6, 10}, {3, 0}, Qt::UTC}) + || now >= QDateTime {{2019, 7, 21}, {0, 0}, Qt::UTC}) + { + Q_EMIT finished (); + } } void MainWindow::initialize_fonts () @@ -1307,7 +1322,9 @@ void MainWindow::fixStop() m_hsymStop=((int(m_TRperiod/0.288))/8)*8; } else if (m_mode=="FT8") { m_hsymStop=50; - } + } else if (m_mode=="FT4") { + m_hsymStop=21; +} } //-------------------------------------------------------------- dataSink() @@ -1315,8 +1332,7 @@ void MainWindow::dataSink(qint64 frames) { static float s[NSMAX]; char line[80]; - - int k (frames); + int k(frames); QString fname {QDir::toNativeSeparators(m_config.writeable_data_dir ().absoluteFilePath ("refspec.dat"))}; QByteArray bafname = fname.toLatin1(); const char *c_fname = bafname.data(); @@ -1339,20 +1355,24 @@ void MainWindow::dataSink(qint64 frames) } // Get power, spectrum, and ihsym - int trmin=m_TRperiod/60; + int trmin=m_TRperiod/60.0; // int k (frames - 1); dec_data.params.nfa=m_wideGraph->nStartFreq(); dec_data.params.nfb=m_wideGraph->Fmax(); int nsps=m_nsps; if(m_bFastMode) nsps=6912; int nsmo=m_wideGraph->smoothYellow()-1; - symspec_(&dec_data,&k,&trmin,&nsps,&m_inGain,&nsmo,&m_px,s,&m_df3,&m_ihsym,&m_npts8,&m_pxmax); + bool bLowSidelobes=m_config.lowSidelobes(); + symspec_(&dec_data,&k,&trmin,&nsps,&m_inGain,&bLowSidelobes,&nsmo,&m_px,s, + &m_df3,&m_ihsym,&m_npts8,&m_pxmax); if(m_mode=="WSPR") wspr_downsample_(dec_data.d2,&k); if(m_ihsym <=0) return; if(ui) ui->signal_meter_widget->setValue(m_px,m_pxmax); // Update thermometer if(m_monitoring || m_diskData) { m_wideGraph->dataSink2(s,m_df3,m_ihsym,m_diskData); } +// if(m_mode=="FT4") ft4_rx(k); +// if(m_mode=="MSK144" or m_mode=="FT4") return; if(m_mode=="MSK144") return; fixStop(); @@ -1432,22 +1452,25 @@ void MainWindow::dataSink(qint64 frames) if(!m_mode.startsWith ("WSPR")) decode(); //Start decoder if(!m_diskData) { //Always save; may delete later - - if(m_mode=="FT8") { - int n=now.time().second() % m_TRperiod; + if(m_mode=="FT8" or m_mode=="FT4") { + int n=fmod(double(now.time().second()),m_TRperiod); if(n<(m_TRperiod/2)) n=n+m_TRperiod; auto const& period_start=now.addSecs(-n); m_fnameWE=m_config.save_directory().absoluteFilePath (period_start.toString("yyMMdd_hhmmss")); +// qDebug() << "datasink 2" << QDateTime::currentDateTimeUtc().toString("ss.zzz") +// << n << period_start.toString("ss.zzz"); } else { - auto const& period_start = now.addSecs (-(now.time ().minute () % (m_TRperiod / 60)) * 60); + auto const& period_start = now.addSecs (-(now.time ().minute () % (int(m_TRperiod) / 60)) * 60); m_fnameWE=m_config.save_directory ().absoluteFilePath (period_start.toString ("yyMMdd_hhmm")); } m_fileToSave.clear (); + int samples=m_TRperiod*12000; + if(m_mode=="FT4") samples=21*3456; // the following is potential a threading hazard - not a good // idea to pass pointer to be processed in another thread m_saveWAVWatcher.setFuture (QtConcurrent::run (std::bind (&MainWindow::save_wave_file, - this, m_fnameWE, &dec_data.d2[0], m_TRperiod, m_config.my_callsign(), + this, m_fnameWE, &dec_data.d2[0], samples, m_config.my_callsign(), m_config.my_grid(), m_mode, m_nSubMode, m_freqNominal, m_hisCall, m_hisGrid))); if (m_mode=="WSPR") { QString c2name_string {m_fnameWE + ".c2"}; @@ -1506,7 +1529,7 @@ void MainWindow::startP1() p1.start(m_cmndP1); } -QString MainWindow::save_wave_file (QString const& name, short const * data, int seconds, +QString MainWindow::save_wave_file (QString const& name, short const * data, int samples, QString const& my_callsign, QString const& my_grid, QString const& mode, qint32 sub_mode, Frequency frequency, QString const& his_call, QString const& his_grid) const { @@ -1542,7 +1565,7 @@ QString MainWindow::save_wave_file (QString const& name, short const * data, int BWFFile wav {format, file_name, list_info}; if (!wav.open (BWFFile::WriteOnly) || 0 > wav.write (reinterpret_cast (data) - , sizeof (short) * seconds * format.sampleRate ())) + , sizeof (short) * samples)) { return file_name + ": " + wav.errorString (); } @@ -1554,7 +1577,6 @@ void MainWindow::fastSink(qint64 frames) { int k (frames); bool decodeNow=false; - if(k < m_k0) { //New sequence ? memcpy(fast_green2,fast_green,4*703); //Copy fast_green[] to fast_green2[] memcpy(fast_s2,fast_s,4*703*64); //Copy fast_s[] into fast_s2[] @@ -1568,7 +1590,7 @@ void MainWindow::fastSink(qint64 frames) int ihr=tnow.toString("hh").toInt(); int imin=tnow.toString("mm").toInt(); int isec=tnow.toString("ss").toInt(); - isec=isec - isec%m_TRperiod; + isec=isec - fmod(double(isec),m_TRperiod); int nutc0=10000*ihr + 100*imin + isec; if(m_diskData) nutc0=m_UTCdisk; char line[80]; @@ -1648,7 +1670,7 @@ void MainWindow::fastSink(qint64 frames) if(decodeNow or m_bFastDone) { if(!m_diskData) { QDateTime now {QDateTime::currentDateTimeUtc()}; - int n=now.time().second() % m_TRperiod; + int n=fmod(double(now.time().second()),m_TRperiod); if(n<(m_TRperiod/2)) n=n+m_TRperiod; auto const& period_start = now.addSecs (-n); m_fnameWE = m_config.save_directory ().absoluteFilePath (period_start.toString ("yyMMdd_hhmmss")); @@ -1658,11 +1680,11 @@ void MainWindow::fastSink(qint64 frames) // the following is potential a threading hazard - not a good // idea to pass pointer to be processed in another thread m_saveWAVWatcher.setFuture (QtConcurrent::run (std::bind (&MainWindow::save_wave_file, - this, m_fnameWE, &dec_data.d2[0], m_TRperiod, m_config.my_callsign(), + this, m_fnameWE, &dec_data.d2[0], int(m_TRperiod*12000.0), m_config.my_callsign(), m_config.my_grid(), m_mode, m_nSubMode, m_freqNominal, m_hisCall, m_hisGrid))); } if(m_mode!="MSK144") { - killFileTimer.start (3*1000*m_TRperiod/4); //Kill 3/4 period from now + killFileTimer.start (int(750.0*m_TRperiod)); //Kill 3/4 period from now } } m_bFastDone=false; @@ -1730,18 +1752,7 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog bool b = vhf && (m_mode=="JT4" or m_mode=="JT65" or m_mode=="ISCAT" or m_mode=="JT9" or m_mode=="MSK144" or m_mode=="QRA64"); if(b) VHF_features_enabled(b); - if(m_mode=="FT8") on_actionFT8_triggered(); - if(m_mode=="JT4") on_actionJT4_triggered(); - if(m_mode=="JT9") on_actionJT9_triggered(); - if(m_mode=="JT9+JT65") on_actionJT9_JT65_triggered(); - if(m_mode=="JT65") on_actionJT65_triggered(); - if(m_mode=="QRA64") on_actionQRA64_triggered(); - if(m_mode=="FreqCal") on_actionFreqCal_triggered(); - if(m_mode=="ISCAT") on_actionISCAT_triggered(); - if(m_mode=="MSK144") on_actionMSK144_triggered(); - if(m_mode=="WSPR") on_actionWSPR_triggered(); - if(m_mode=="WSPR-LF") on_actionWSPR_LF_triggered(); - if(m_mode=="Echo") on_actionEcho_triggered(); + set_mode (m_mode); if(b) VHF_features_enabled(b); m_config.transceiver_online (); @@ -1761,6 +1772,7 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog ui->actionEnable_AP_JT65->setVisible(false); } if(m_config.special_op_id()!=nContest0) ui->tx1->setEnabled(true); + chkFT4(); } } @@ -1870,9 +1882,20 @@ void MainWindow::keyPressEvent (QKeyEvent * e) } int n; - bool bAltF1F5=m_config.alternate_bindings(); + bool bAltF1F6=m_config.alternate_bindings(); switch(e->key()) { + case Qt::Key_B: + if(m_mode=="FT4" && e->modifiers() & Qt::AltModifier) { + on_pbBestSP_clicked(); + } + return; + case Qt::Key_C: + if(m_mode=="FT4" && e->modifiers() & Qt::AltModifier) { + bool b=ui->cbFirst->isChecked(); + ui->cbFirst->setChecked(!b); + } + return; case Qt::Key_D: if(m_mode != "WSPR" && e->modifiers() & Qt::ShiftModifier) { if(!m_decoderBusy) { @@ -1884,7 +1907,7 @@ void MainWindow::keyPressEvent (QKeyEvent * e) } break; case Qt::Key_F1: - if(bAltF1F5) { + if(bAltF1F6) { auto_tx_mode(true); on_txb6_clicked(); return; @@ -1893,7 +1916,7 @@ void MainWindow::keyPressEvent (QKeyEvent * e) return; } case Qt::Key_F2: - if(bAltF1F5) { + if(bAltF1F6) { auto_tx_mode(true); on_txb2_clicked(); return; @@ -1902,7 +1925,7 @@ void MainWindow::keyPressEvent (QKeyEvent * e) return; } case Qt::Key_F3: - if(bAltF1F5) { + if(bAltF1F6) { auto_tx_mode(true); on_txb3_clicked(); return; @@ -1911,7 +1934,7 @@ void MainWindow::keyPressEvent (QKeyEvent * e) return; } case Qt::Key_F4: - if(bAltF1F5) { + if(bAltF1F6) { auto_tx_mode(true); on_txb4_clicked(); return; @@ -1921,7 +1944,7 @@ void MainWindow::keyPressEvent (QKeyEvent * e) return; } case Qt::Key_F5: - if(bAltF1F5) { + if(bAltF1F6) { auto_tx_mode(true); on_txb5_clicked(); return; @@ -1930,11 +1953,16 @@ void MainWindow::keyPressEvent (QKeyEvent * e) return; } case Qt::Key_F6: - if(e->modifiers() & Qt::ShiftModifier) { - on_actionDecode_remaining_files_in_directory_triggered(); - return; + if(bAltF1F6) { + bool b=ui->cbFirst->isChecked(); + ui->cbFirst->setChecked(!b); + } else { + if(e->modifiers() & Qt::ShiftModifier) { + on_actionDecode_remaining_files_in_directory_triggered(); + } else { + on_actionOpen_next_in_directory_triggered(); + } } - on_actionOpen_next_in_directory_triggered(); return; case Qt::Key_F11: if((e->modifiers() & Qt::ControlModifier) and (e->modifiers() & Qt::ShiftModifier)) { @@ -1944,7 +1972,9 @@ void MainWindow::keyPressEvent (QKeyEvent * e) n=11; if(e->modifiers() & Qt::ControlModifier) n+=100; if(e->modifiers() & Qt::ShiftModifier) { - ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()-60); + int offset=60; + if(m_mode=="FT4") offset=90; + ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()-offset); } else{ bumpFqso(n); } @@ -1958,7 +1988,9 @@ void MainWindow::keyPressEvent (QKeyEvent * e) n=12; if(e->modifiers() & Qt::ControlModifier) n+=100; if(e->modifiers() & Qt::ShiftModifier) { - ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()+60); + int offset=60; + if(m_mode=="FT4") offset=90; + ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()+offset); } else { bumpFqso(n); } @@ -1971,11 +2003,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e) on_stopTxButton_clicked(); abortQSO(); return; - case Qt::Key_X: - if(e->modifiers() & Qt::AltModifier) { - foxTest(); - return; - } case Qt::Key_E: if((e->modifiers() & Qt::ShiftModifier) and SpecOp::FOX > m_config.special_op_id()) { ui->txFirstCheckBox->setChecked(false); @@ -2022,6 +2049,15 @@ void MainWindow::keyPressEvent (QKeyEvent * e) on_actionOpen_triggered(); return; } + else if(e->modifiers() & Qt::AltModifier) { + bool ok; + auto call = QInputDialog::getText (this, tr ("Change Operator"), tr ("New operator:"), + QLineEdit::Normal, m_config.opCall (), &ok); + if (ok) { + m_config.opCall (call); + } + return; + } break; case Qt::Key_V: if(e->modifiers() & Qt::AltModifier) { @@ -2180,7 +2216,6 @@ void MainWindow::createStatusBar() //createStatusBar statusBar()->addPermanentWidget(&progressBar); progressBar.setMinimumSize (QSize {150, 18}); - progressBar.setFormat ("%v/%m"); statusBar ()->addPermanentWidget (&watchdog_label); update_watchdog_label (); @@ -2491,16 +2526,14 @@ void MainWindow::on_actionAstronomical_data_toggled (bool checked) void MainWindow::on_fox_log_action_triggered() { - if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config}); if (!m_foxLogWindow) { - m_foxLogWindow.reset (new FoxLogWindow {m_settings, &m_config, m_foxLog.data ()}); + m_foxLogWindow.reset (new FoxLogWindow {m_settings, &m_config, m_logBook.fox_log ()}); // Connect signals from fox log window connect (this, &MainWindow::finished, m_foxLogWindow.data (), &FoxLogWindow::close); connect (m_foxLogWindow.data (), &FoxLogWindow::reset_log_model, [this] () { - if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config}); - m_foxLog->reset (); + m_logBook.fox_log ()->reset (); }); } m_foxLogWindow->showNormal (); @@ -2510,10 +2543,9 @@ void MainWindow::on_fox_log_action_triggered() void MainWindow::on_contest_log_action_triggered() { - if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); if (!m_contestLogWindow) { - m_contestLogWindow.reset (new CabrilloLogWindow {m_settings, &m_config, m_cabrilloLog->model ()}); + m_contestLogWindow.reset (new CabrilloLogWindow {m_settings, &m_config, m_logBook.contest_log ()->model ()}); // Connect signals from contest log window connect (this, &MainWindow::finished, m_contestLogWindow.data (), &CabrilloLogWindow::close); @@ -2593,7 +2625,8 @@ void MainWindow::read_wav_file (QString const& fname) bool ok=file.open (BWFFile::ReadOnly); if(ok) { auto bytes_per_frame = file.format ().bytesPerFrame (); - qint64 max_bytes = std::min (std::size_t (m_TRperiod * RX_SAMPLE_RATE), + int nsamples=m_TRperiod * RX_SAMPLE_RATE; + qint64 max_bytes = std::min (std::size_t (nsamples), sizeof (dec_data.d2) / sizeof (dec_data.d2[0]))* bytes_per_frame; auto n = file.read (reinterpret_cast (dec_data.d2), std::min (max_bytes, file.size ())); @@ -2663,7 +2696,8 @@ void MainWindow::diskDat() //diskDat() float bw=m_config.RxBandwidth(); if(db > 0.0) degrade_snr_(dec_data.d2,&dec_data.params.kin,&db,&bw); for(int n=1; n<=m_hsymStop; n++) { // Do the waterfall spectra - k=(n+1)*kstep; +// k=(n+1)*kstep; //### Why was this (n+1) ??? ### + k=n*kstep; if(k > dec_data.params.kin) break; dec_data.params.npts8=k/8; dataSink(k); @@ -2772,7 +2806,7 @@ void MainWindow::decode() //decode() QDateTime now = QDateTime::currentDateTimeUtc (); if( m_dateTimeLastTX.isValid () ) { qint64 isecs_since_tx = m_dateTimeLastTX.secsTo(now); - dec_data.params.lapcqonly= (isecs_since_tx > 600); + dec_data.params.lapcqonly= (isecs_since_tx > 300); // QTextStream(stdout) << "last tx " << isecs_since_tx << endl; } else { m_dateTimeLastTX = now.addSecs(-900); @@ -2783,9 +2817,9 @@ void MainWindow::decode() //decode() } m_msec0=QDateTime::currentMSecsSinceEpoch(); - if(!m_dataAvailable or m_TRperiod==0) return; + if(!m_dataAvailable or m_TRperiod==0.0) return; ui->DecodeButton->setChecked (true); - if(!dec_data.params.nagain && m_diskData && !m_bFastMode && m_mode!="FT8") { + if(!dec_data.params.nagain && m_diskData && !m_bFastMode && m_mode!="FT8" && m_mode!="FT4") { dec_data.params.nutc=dec_data.params.nutc/100; } if(dec_data.params.nagain==0 && dec_data.params.newdat==1 && (!m_diskData)) { @@ -2793,14 +2827,16 @@ void MainWindow::decode() //decode() int imin=ms/60000; int ihr=imin/60; imin=imin % 60; - if(m_TRperiod>=60) imin=imin - (imin % (m_TRperiod/60)); + if(m_TRperiod>=60) imin=imin - (imin % (int(m_TRperiod)/60)); dec_data.params.nutc=100*ihr + imin; - if(m_mode=="ISCAT" or m_mode=="MSK144" or m_bFast9 or m_mode=="FT8") { - QDateTime t=QDateTime::currentDateTimeUtc().addSecs(2-m_TRperiod); + if(m_mode=="ISCAT" or m_mode=="MSK144" or m_bFast9 or m_mode=="FT8" or m_mode=="FT4") { + qint64 ms=1000.0*(2.0-m_TRperiod); + if(m_mode=="FT4") ms=1000.0*(2.0-m_TRperiod); + QDateTime t=QDateTime::currentDateTimeUtc().addMSecs(ms); ihr=t.toString("hh").toInt(); imin=t.toString("mm").toInt(); int isec=t.toString("ss").toInt(); - isec=isec - isec%m_TRperiod; + isec=isec - fmod(double(isec),m_TRperiod); dec_data.params.nutc=10000*ihr + 100*imin + isec; } } @@ -2810,7 +2846,7 @@ void MainWindow::decode() //decode() int ihr=t.toString("hh").toInt(); int imin=t.toString("mm").toInt(); int isec=t.toString("ss").toInt(); - isec=isec - isec%m_TRperiod; + isec=isec - fmod(double(isec),m_TRperiod); dec_data.params.nutc=10000*ihr + 100*imin + isec; } if(m_nPick==2) dec_data.params.nutc=m_nutc0; @@ -2845,7 +2881,8 @@ void MainWindow::decode() //decode() if(m_modeTx=="JT65") dec_data.params.ntxmode=65; dec_data.params.nmode=9; if(m_mode=="JT65") dec_data.params.nmode=65; - if(m_mode=="JT65") dec_data.params.ljt65apon = ui->actionEnable_AP_JT65->isVisible () && ui->actionEnable_AP_JT65->isChecked (); + if(m_mode=="JT65") dec_data.params.ljt65apon = ui->actionEnable_AP_JT65->isVisible () && + ui->actionEnable_AP_JT65->isChecked (); if(m_mode=="QRA64") dec_data.params.nmode=164; if(m_mode=="QRA64") dec_data.params.ntxmode=164; if(m_mode=="JT9+JT65") dec_data.params.nmode=9+65; // = 74 @@ -2854,8 +2891,13 @@ void MainWindow::decode() //decode() dec_data.params.ntxmode=4; } if(m_mode=="FT8") dec_data.params.nmode=8; - if(m_mode=="FT8") dec_data.params.lft8apon = ui->actionEnable_AP_FT8->isVisible () && ui->actionEnable_AP_FT8->isChecked (); + if(m_mode=="FT8") dec_data.params.lft8apon = ui->actionEnable_AP_FT8->isVisible () && + ui->actionEnable_AP_FT8->isChecked (); if(m_mode=="FT8") dec_data.params.napwid=50; + if(m_mode=="FT4") { + dec_data.params.nmode=5; + m_BestCQpriority=""; + } dec_data.params.ntrperiod=m_TRperiod; dec_data.params.nsubmode=m_nSubMode; if(m_mode=="QRA64") dec_data.params.nsubmode=100 + m_nSubMode; @@ -2903,8 +2945,8 @@ void MainWindow::decode() //decode() } static short int d2b[360000]; narg[0]=dec_data.params.nutc; - if(m_kdone>12000*m_TRperiod) { - m_kdone=12000*m_TRperiod; + if(m_kdone>int(12000.0*m_TRperiod)) { + m_kdone=int(12000.0*m_TRperiod); } narg[1]=m_kdone; narg[2]=m_nSubMode; @@ -3000,7 +3042,7 @@ void MainWindow::readFromStdout() //readFromStdout // truncate before line ending chars line_read = line_read.left (p - line_read.constData ()); } - if(m_mode!="FT8") { + if(m_mode!="FT8" and m_mode!="FT4") { //Pad 22-char msg to at least 37 chars line_read = line_read.left(43) + " " + line_read.mid(43); } @@ -3010,7 +3052,7 @@ void MainWindow::readFromStdout() //readFromStdout if(line_read.indexOf("") >= 0) { if(m_mode=="QRA64") m_wideGraph->drawRed(0,0); m_bDecoded = line_read.mid(20).trimmed().toInt() > 0; - int mswait=3*1000*m_TRperiod/4; + int mswait=750.0*m_TRperiod; if(!m_diskData) killFileTimer.start(mswait); //Kill in 3/4 period decodeDone (); m_startAnother=m_loopall; @@ -3020,7 +3062,7 @@ void MainWindow::readFromStdout() //readFromStdout } return; } else { - if(m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64" or m_mode=="FT8") { + if(m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64") { int n=line_read.indexOf("f"); if(n<0) n=line_read.indexOf("d"); if(n>0) { @@ -3036,7 +3078,7 @@ void MainWindow::readFromStdout() //readFromStdout write_all("Rx",line_read.trimmed()); if (m_config.insert_blank () && m_blankLine && SpecOp::FOX != m_config.special_op_id()) { QString band; - if((QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged) > 4*m_TRperiod/4) { + if((QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged) > 4*int(m_TRperiod)/4) { band = ' ' + m_config.bands ()->find (m_freqNominal); } ui->decodedTextBrowser->insertLineSpacer (band.rightJustified (40, '-')); @@ -3074,17 +3116,33 @@ void MainWindow::readFromStdout() //readFromStdout ui->decodedTextBrowser->displayDecodedText(decodedtext0,m_baseCall,m_mode,m_config.DXCC(), m_logBook,m_currentBand,m_config.ppfx(), (ui->cbCQonly->isVisible() and ui->cbCQonly->isChecked())); + if(m_bBestSPArmed and m_mode=="FT4") { + QString messagePriority=ui->decodedTextBrowser->CQPriority(); + if(messagePriority!="") { + if(messagePriority=="New Call on Band" + and m_BestCQpriority!="New Call on Band" + and m_BestCQpriority!="New Multiplier") { + m_BestCQpriority="New Call on Band"; + processMessage(decodedtext0); + } + if(messagePriority=="New DXCC" + and m_BestCQpriority!="New DXCC" + and m_BestCQpriority!="New Multiplier") { + m_BestCQpriority="New DXCC"; + processMessage(decodedtext0); + } + } + } } } //Right (Rx Frequency) window bool bDisplayRight=bAvgMsg; int audioFreq=decodedtext.frequencyOffset(); - - if(m_mode=="FT8") { + if(m_mode=="FT8" or m_mode=="FT4") { auto const& parts = decodedtext.string().remove("<").remove(">") .split (' ', QString::SkipEmptyParts); - if (parts.size () > 6) { + if (parts.size() > 6) { auto for_us = parts[5].contains (m_baseCall) || ("DE" == parts[5] && qAbs (ui->RxFreqSpinBox->value () - audioFreq) <= 10); if(m_baseCall==m_config.my_callsign() and m_baseCall!=parts[5]) for_us=false; @@ -3106,9 +3164,10 @@ void MainWindow::readFromStdout() //readFromStdout if (bDisplayRight) { // This msg is within 10 hertz of our tuned frequency, or a JT4 or JT65 avg, // or contains MyCall - ui->decodedTextBrowser2->displayDecodedText(decodedtext0,m_baseCall,m_mode,m_config.DXCC(), - m_logBook,m_currentBand,m_config.ppfx()); - + if(!m_bBestSPArmed or m_mode!="FT4") { + ui->decodedTextBrowser2->displayDecodedText(decodedtext0,m_baseCall,m_mode,m_config.DXCC(), + m_logBook,m_currentBand,m_config.ppfx()); + } if(m_mode!="JT4") { bool b65=decodedtext.isJT65(); if(b65 and m_modeTx!="JT65") on_pbTxMode_clicked(); @@ -3162,7 +3221,7 @@ void MainWindow::readFromStdout() //readFromStdout //### I think this is where we are preventing Hounds from spotting Fox ### if(m_mode!="FT8" or (SpecOp::HOUND != m_config.special_op_id())) { - if(m_mode=="FT8" or m_mode=="QRA64" or m_mode=="JT4" or m_mode=="JT65" or m_mode=="JT9") { + if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="QRA64" or m_mode=="JT4" or m_mode=="JT65" or m_mode=="JT9") { auto_sequence (decodedtext, 25, 50); } @@ -3179,7 +3238,7 @@ void MainWindow::readFromStdout() //readFromStdout } // extract details and send to PSKreporter int nsec=QDateTime::currentMSecsSinceEpoch()/1000-m_secBandChanged; - bool okToPost=(nsec>(4*m_TRperiod)/5); + bool okToPost=(nsec > int(4*m_TRperiod)/5); if (stdMsg && okToPost) pskPost(decodedtext); if((m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64") and m_msgAvgWidget!=NULL) { @@ -3279,7 +3338,7 @@ void MainWindow::pskPost (DecodedText const& decodedtext) QString grid; decodedtext.deCallAndGrid(/*out*/deCall,grid); int audioFrequency = decodedtext.frequencyOffset(); - if(m_mode=="FT8" or m_mode=="MSK144") { + if(m_mode=="FT8" or m_mode=="MSK144" or m_mode=="FT4") { audioFrequency=decodedtext.string().mid(16,4).toInt(); } int snr = decodedtext.snr(); @@ -3359,8 +3418,9 @@ void MainWindow::guiUpdate() double txDuration; QString rt; - if(m_TRperiod==0) m_TRperiod=60; + if(m_TRperiod==0) m_TRperiod=60.0; txDuration=0.0; + if(m_modeTx=="FT4") txDuration=1.0 + 105*576/12000.0; // FT4 if(m_modeTx=="FT8") txDuration=1.0 + 79*1920/12000.0; // FT8 if(m_modeTx=="JT4") txDuration=1.0 + 207.0*2520/11025.0; // JT4 if(m_modeTx=="JT9") txDuration=1.0 + 85.0*m_nsps/12000.0; // JT9 @@ -3374,7 +3434,7 @@ void MainWindow::guiUpdate() double tx1=0.0; double tx2=txDuration; - if(m_mode=="FT8") icw[0]=0; //No CW ID in FT8 mode + if(m_mode=="FT8" or m_mode=="FT4") icw[0]=0; //No CW ID in FT4 or FT8 mode if((icw[0]>0) and (!m_bFast9)) tx2 += icw[0]*2560.0/48000.0; //Full length including CW ID if(tx2>m_TRperiod) tx2=m_TRperiod; @@ -3388,8 +3448,8 @@ void MainWindow::guiUpdate() double tsec=0.001*ms; double t2p=fmod(tsec,2*m_TRperiod); m_s6=fmod(tsec,6.0); - m_nseq = nsec % m_TRperiod; - m_tRemaining=m_TRperiod - fmod(tsec,double(m_TRperiod)); + m_nseq = fmod(double(nsec),m_TRperiod); + m_tRemaining=m_TRperiod - fmod(tsec,m_TRperiod); if(m_mode=="Echo") { txDuration=2.4; @@ -3430,10 +3490,9 @@ void MainWindow::guiUpdate() if(m_transmitting or m_auto or m_tune) { m_dateTimeLastTX = QDateTime::currentDateTimeUtc (); -// Check for "txboth" (testing purposes only) +// Check for "txboth" (FT4 testing purposes only) QFile f(m_appDir + "/txboth"); - if(f.exists() and - fmod(tsec,m_TRperiod)<(1.0 + 85.0*m_nsps/12000.0)) m_bTxTime=true; + if(f.exists() and fmod(tsec,m_TRperiod) < (0.5 + 105.0*576.0/12000.0)) m_bTxTime=true; // Don't transmit another mode in the 30 m WSPR sub-band Frequency onAirFreq = m_freqNominal + ui->TxFreqSpinBox->value(); @@ -3476,7 +3535,7 @@ void MainWindow::guiUpdate() tx_watchdog (true); // disable transmit } - float fTR=float((ms%(1000*m_TRperiod)))/(1000*m_TRperiod); + float fTR=float((ms%int(1000.0*m_TRperiod)))/int(1000.0*m_TRperiod); QString txMsg; if(m_ntx == 1) txMsg=ui->tx1->text(); @@ -3532,6 +3591,7 @@ void MainWindow::guiUpdate() Q_EMIT m_config.transceiver_ptt (true); //Assert the PTT m_tx_when_ready = true; } +// if(!m_bTxTime and !m_tune and m_mode!="FT4") m_btxok=false; //Time to stop transmitting if(!m_bTxTime and !m_tune) m_btxok=false; //Time to stop transmitting } @@ -3583,6 +3643,13 @@ void MainWindow::guiUpdate() m_ntx=1; ui->txrb1->setChecked(true); } + + if(m_mode=="FT4" and m_bBestSPArmed) { + m_BestCQpriority=""; + m_bBestSPArmed=false; + ui->pbBestSP->setStyleSheet (""); + } + if(m_ntx == 1) ba=ui->tx1->text().toLocal8Bit(); if(m_ntx == 2) ba=ui->tx2->text().toLocal8Bit(); if(m_ntx == 3) ba=ui->tx3->text().toLocal8Bit(); @@ -3621,7 +3688,7 @@ void MainWindow::guiUpdate() 22, 22); // if(m_modeTx=="WSPR-LF") genwspr_fsk8_(message, msgsent, const_cast (itone), // 22, 22); - if(m_modeTx=="MSK144" or m_modeTx=="FT8") { + if(m_modeTx=="MSK144" or m_modeTx=="FT8" or m_modeTx=="FT4") { char MyCall[6]; char MyGrid[6]; strncpy(MyCall, (m_config.my_callsign()+" ").toLatin1(),6); @@ -3644,6 +3711,16 @@ void MainWindow::guiUpdate() char ft8msgbits[77]; genft8_(message, &i3, &n3, msgsent, const_cast (ft8msgbits), const_cast (itone), 37, 37); + int nsym=79; + int nsps=4*1920; + float fsample=48000.0; + float bt=2.0; + float f0=ui->TxFreqSpinBox->value() - m_XIT; + int icmplx=0; + int nwave=nsym*nsps; + gen_ft8wave_(const_cast(itone),&nsym,&nsps,&bt,&fsample,&f0,foxcom_.wave, + foxcom_.wave,&icmplx,&nwave); + if(SpecOp::FOX == m_config.special_op_id()) { //Fox must generate the full Tx waveform, not just an itone[] array. QString fm = QString::fromStdString(message).trimmed(); @@ -3657,6 +3734,21 @@ void MainWindow::guiUpdate() } } } + if(m_modeTx=="FT4") { + int ichk=0; + char ft4msgbits[77]; + genft4_(message, &ichk, msgsent, const_cast (ft4msgbits), + const_cast(itone), 37, 37); + int nsym=103; + int nsps=4*576; + float fsample=48000.0; + float f0=ui->TxFreqSpinBox->value() - m_XIT; + int nwave=(nsym+2)*nsps; + int icmplx=0; + gen_ft4wave_(const_cast(itone),&nsym,&nsps,&fsample,&f0,foxcom_.wave, + foxcom_.wave,&icmplx,&nwave); + } + if(SpecOp::EU_VHF==m_config.special_op_id()) { if(m_ntx==2) m_xSent=ui->tx2->text().right(13); if(m_ntx==3) m_xSent=ui->tx3->text().right(13); @@ -3677,7 +3769,7 @@ void MainWindow::guiUpdate() m_currentMessage = QString::fromLatin1(msgsent); m_bCallingCQ = CALLING == m_QSOProgress || m_currentMessage.contains (QRegularExpression {"^(CQ|QRZ) "}); - if(m_mode=="FT8") { + if(m_mode=="FT8" or m_mode=="FT4") { if(m_bCallingCQ && ui->cbFirst->isVisible () && ui->cbFirst->isChecked ()) { ui->cbFirst->setStyleSheet("QCheckBox{color:red}"); } else { @@ -3719,7 +3811,7 @@ void MainWindow::guiUpdate() if((m_config.prompt_to_log() or m_config.autoLog()) && !m_tune) logQSOTimer.start(0); } - bool b=(m_mode=="FT8") and ui->cbAutoSeq->isChecked(); + bool b=(m_mode=="FT8" or m_mode=="FT4") and ui->cbAutoSeq->isChecked(); if(is_73 and (m_config.disable_TX_on_73() or b)) { m_nextCall=""; //### Temporary: disable use of "TU;" messages; if(m_nextCall!="") { @@ -3784,36 +3876,37 @@ void MainWindow::guiUpdate() } } - if (g_iptt == 1 && m_iptt0 == 0) - { - auto const& current_message = QString::fromLatin1 (msgsent); - if(m_config.watchdog () && !m_mode.startsWith ("WSPR") - && current_message != m_msgSent0) { - tx_watchdog (false); // in case we are auto sequencing - m_msgSent0 = current_message; - } + if (g_iptt == 1 && m_iptt0 == 0) { + auto const& current_message = QString::fromLatin1 (msgsent); + if(m_config.watchdog () && !m_mode.startsWith ("WSPR") + && current_message != m_msgSent0) { + tx_watchdog (false); // in case we are auto sequencing + m_msgSent0 = current_message; + } +// if(m_mode!="FT4") { if(!m_tune) write_all("Tx",m_currentMessage); if (m_config.TX_messages () && !m_tune && SpecOp::FOX!=m_config.special_op_id()) { ui->decodedTextBrowser2->displayTransmittedText(current_message, m_modeTx, - ui->TxFreqSpinBox->value(),m_bFastMode); + ui->TxFreqSpinBox->value(),m_bFastMode); } +// } - switch (m_ntx) - { - case 1: m_QSOProgress = REPLYING; break; - case 2: m_QSOProgress = REPORT; break; - case 3: m_QSOProgress = ROGER_REPORT; break; - case 4: m_QSOProgress = ROGERS; break; - case 5: m_QSOProgress = SIGNOFF; break; - case 6: m_QSOProgress = CALLING; break; - default: break; // determined elsewhere - } - m_transmitting = true; - transmitDisplay (true); - statusUpdate (); + switch (m_ntx) + { + case 1: m_QSOProgress = REPLYING; break; + case 2: m_QSOProgress = REPORT; break; + case 3: m_QSOProgress = ROGER_REPORT; break; + case 4: m_QSOProgress = ROGERS; break; + case 5: m_QSOProgress = SIGNOFF; break; + case 6: m_QSOProgress = CALLING; break; + default: break; // determined elsewhere } + m_transmitting = true; + transmitDisplay (true); + statusUpdate (); + } if(!m_btxok && m_btxok0 && g_iptt==1) stopTx(); @@ -3828,22 +3921,25 @@ void MainWindow::guiUpdate() } } - if(m_mode=="FT8" or m_mode=="MSK144") { + if(m_mode=="FT8" or m_mode=="MSK144" or m_mode=="FT4") { if(ui->txrb1->isEnabled() and (SpecOp::NA_VHF==m_config.special_op_id() or SpecOp::FIELD_DAY==m_config.special_op_id() or SpecOp::RTTY==m_config.special_op_id()) ) { //We're in a contest-like mode other than EU_VHF: start QSO with Tx2. ui->tx1->setEnabled(false); + ui->txb1->setEnabled(false); } if(!ui->tx1->isEnabled() and SpecOp::EU_VHF==m_config.special_op_id()) { //We're in EU_VHF mode: start QSO with Tx1. ui->tx1->setEnabled(true); + ui->txb1->setEnabled(true); } } //Once per second: if(nsec != m_sec0) { +// qDebug() << "onesec" << m_config.force_call_1st(); // if((!m_msgAvgWidget or (m_msgAvgWidget and !m_msgAvgWidget->isVisible())) // and (SpecOp::NONE < m_config.special_op_id()) and (SpecOp::HOUND > m_config.special_op_id())) on_actionFox_Log_triggered(); if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) { @@ -3858,15 +3954,22 @@ void MainWindow::guiUpdate() //To keep calling Fox, Hound must reactivate Enable Tx at least once every 2 minutes if(tHound >= 120 and m_ntx==1) auto_tx_mode(false); } + + progressBar.setVisible(true); + progressBar.setFormat ("%v/%m"); if(m_auto and m_mode=="Echo" and m_bEchoTxOK) { - progressBar.setMaximum(6); + progressBar.setMaximum(3); progressBar.setValue(int(m_s6)); } - if(m_mode!="Echo") { if(m_monitoring or m_transmitting) { progressBar.setMaximum(m_TRperiod); int isec=int(fmod(tsec,m_TRperiod)); + if(m_TRperiod-int(m_TRperiod)>0.0) { + QString progBarLabel; + progBarLabel.sprintf("%d/%3.1f",isec,m_TRperiod); + progressBar.setFormat (progBarLabel); + } progressBar.setValue(isec); } else { progressBar.setValue(0); @@ -3902,6 +4005,7 @@ void MainWindow::guiUpdate() if(SpecOp::FOX==m_config.special_op_id() and ui->tabWidget->currentIndex()==2 and foxcom_.nslots==1) { t=m_fm1.trimmed(); } + if(m_mode=="FT4") t="Tx: "+ m_currentMessage; tx_status_label.setText(t.trimmed()); } } @@ -3927,9 +4031,8 @@ void MainWindow::guiUpdate() QString utc = t.date().toString("yyyy MMM dd") + "\n " + t.time().toString() + " "; ui->labUTC->setText(utc); - if(!m_monitoring and !m_diskData) { - ui->signal_meter_widget->setValue(0,0); - } + if(m_bBestSPArmed and (m_dateTimeBestSP.secsTo(t) >= 120)) on_pbBestSP_clicked(); //BestSP timeout + if(!m_monitoring and !m_diskData) ui->signal_meter_widget->setValue(0,0); m_sec0=nsec; displayDialFrequency (); } @@ -3965,6 +4068,10 @@ void MainWindow::startTx2() t=ui->tx6->text(); if(t.mid(0,1)=="#") snr=t.mid(1,5).toDouble(); if(snr>0.0 or snr < -50.0) snr=99.0; + if((m_ntx==6 or m_ntx==7) and m_config.force_call_1st()) { + ui->cbAutoSeq->setChecked(true); + ui->cbFirst->setChecked(true); + } transmit (snr); ui->signal_meter_widget->setValue(0,0); if(m_mode=="Echo" and !m_tune) m_bTransmittedEcho=true; @@ -3977,7 +4084,6 @@ void MainWindow::startTx2() ui->decodedTextBrowser->appendText(t); } write_all("Tx",m_currentMessage); -// write_transmit_entry ("ALL_WSPR.TXT"); } } } @@ -4006,13 +4112,12 @@ void MainWindow::stopTx2() on_stopTxButton_clicked (); m_nTx73 = 0; } - if(m_mode.startsWith ("WSPR") and m_ntr==-1 and !m_tuneup) { + if((m_mode.startsWith("WSPR") and m_ntr==-1) and !m_tuneup) { m_wideGraph->setWSPRtransmitted(); WSPR_scheduling (); m_ntr=0; } last_tx_label.setText("Last Tx: " + m_currentMessage.trimmed()); -//### if(m_mode=="FT8" and (SpecOp::HOUND == m_config.special_op_id())) auto_tx_mode(false); ### } void MainWindow::ba2msg(QByteArray ba, char message[]) //ba2msg() @@ -4051,7 +4156,8 @@ void MainWindow::set_dateTimeQSO(int m_ntx) } else { // we also take of m_TRperiod/2 to allow for late clicks auto now = QDateTime::currentDateTimeUtc(); - m_dateTimeQSOOn = now.addSecs (-(m_ntx - 2) * m_TRperiod - (now.time ().second () % m_TRperiod)); + m_dateTimeQSOOn = now.addSecs (-(m_ntx - 2) * int(m_TRperiod) - + int(fmod(double(now.time().second()),m_TRperiod))); } } @@ -4117,6 +4223,7 @@ void MainWindow::on_txrb4_doubleClicked () auto const& my_callsign = m_config.my_callsign (); auto is_compound = my_callsign != m_baseCall; m_send_RR73 = !((is_compound && !shortList (my_callsign)) || m_send_RR73); + if(m_mode=="FT4" and (m_config.special_op_id()==SpecOp::RTTY)) m_send_RR73=true; genStdMsgs (m_rpt); } @@ -4146,7 +4253,7 @@ void MainWindow::on_txb1_clicked() m_ntx=1; m_QSOProgress = REPLYING; ui->txrb1->setChecked(true); - if (m_transmitting) m_restart=true; + if(m_transmitting) m_restart=true; } else { on_txb2_clicked (); @@ -4167,7 +4274,7 @@ void MainWindow::on_txb2_clicked() m_ntx=2; m_QSOProgress = REPORT; ui->txrb2->setChecked(true); - if (m_transmitting) m_restart=true; + if(m_transmitting) m_restart=true; } void MainWindow::on_txb3_clicked() @@ -4175,7 +4282,7 @@ void MainWindow::on_txb3_clicked() m_ntx=3; m_QSOProgress = ROGER_REPORT; ui->txrb3->setChecked(true); - if (m_transmitting) m_restart=true; + if(m_transmitting) m_restart=true; } void MainWindow::on_txb4_clicked() @@ -4183,7 +4290,7 @@ void MainWindow::on_txb4_clicked() m_ntx=4; m_QSOProgress = ROGERS; ui->txrb4->setChecked(true); - if (m_transmitting) m_restart=true; + if(m_transmitting) m_restart=true; } void MainWindow::on_txb4_doubleClicked() @@ -4192,6 +4299,7 @@ void MainWindow::on_txb4_doubleClicked() auto const& my_callsign = m_config.my_callsign (); auto is_compound = my_callsign != m_baseCall; m_send_RR73 = !((is_compound && !shortList (my_callsign)) || m_send_RR73); + if(m_mode=="FT4") m_send_RR73=true; genStdMsgs (m_rpt); } @@ -4200,7 +4308,7 @@ void MainWindow::on_txb5_clicked() m_ntx=5; m_QSOProgress = SIGNOFF; ui->txrb5->setChecked(true); - if (m_transmitting) m_restart=true; + if(m_transmitting) m_restart=true; } void MainWindow::on_txb5_doubleClicked() @@ -4214,11 +4322,12 @@ void MainWindow::on_txb6_clicked() m_QSOProgress = CALLING; set_dateTimeQSO(-1); ui->txrb6->setChecked(true); - if (m_transmitting) m_restart=true; + if(m_transmitting) m_restart=true; } void MainWindow::doubleClickOnCall2(Qt::KeyboardModifiers modifiers) { +//Confusing: come here after double-click on left text window, not right window. set_dateTimeQSO(-1); // reset our QSO start time m_decodedText2=true; doubleClickOnCall(modifiers); @@ -4227,10 +4336,6 @@ void MainWindow::doubleClickOnCall2(Qt::KeyboardModifiers modifiers) void MainWindow::doubleClickOnCall(Qt::KeyboardModifiers modifiers) { -// if(!(modifiers & Qt::AltModifier) and m_transmitting) { -// qDebug() << "aa" << "Double-click on decode is ignored while transmitting"; -// return; -// } QTextCursor cursor; if(m_mode=="ISCAT") { MessageBox::information_message (this, @@ -4256,7 +4361,7 @@ void MainWindow::doubleClickOnCall(Qt::KeyboardModifiers modifiers) } return; } - DecodedText message {cursor.block().text()}; + DecodedText message {cursor.block().text().trimmed().remove("TU; ")}; m_bDoubleClicked = true; processMessage (message, modifiers); } @@ -4267,7 +4372,6 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie auto shift = modifiers.testFlag (Qt::ShiftModifier); auto ctrl = modifiers.testFlag (Qt::ControlModifier); // auto alt = modifiers.testFlag (Qt::AltModifier); - // basic mode sanity checks auto const& parts = message.string ().split (' ', QString::SkipEmptyParts); if (parts.size () < 5) return; @@ -4277,7 +4381,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie || ("JT9" == m_mode && mode != "@") || ("MSK144" == m_mode && !("&" == mode || "^" == mode)) || ("QRA64" == m_mode && mode.left (1) != ":")) { - return; + return; //Currently we do auto-sequencing only in FT4, FT8, and MSK144 } //Skip the rest if no decoded text extracted @@ -4306,7 +4410,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } } - int nmod = message.timeInSeconds () % (2*m_TRperiod); + int nmod = fmod(double(message.timeInSeconds()),2.0*m_TRperiod); m_txFirst=(nmod!=0); if( SpecOp::HOUND == m_config.special_op_id() ) m_txFirst=false; //Hound must not transmit first if( SpecOp::FOX == m_config.special_op_id() ) m_txFirst=true; //Fox must always transmit first @@ -4366,7 +4470,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie ui->TxFreqSpinBox->setValue(frequency); } if(m_mode != "JT4" && m_mode != "JT65" && !m_mode.startsWith ("JT9") && - m_mode != "QRA64" && m_mode!="FT8") { + m_mode != "QRA64" && m_mode!="FT8" && m_mode!="FT4") { return; } } @@ -4429,11 +4533,11 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie // ### Should be in RTTY contest mode ??? ### MessageBox::information_message (this, tr ("Should you switch to RTTY contest mode?")); } - if(message_words.size () > 3 // enough fields for a normal message && (message_words.at(1).contains(m_baseCall) || "DE" == message_words.at(1)) // && (message_words.at(2).contains(qso_partner_base_call) or bEU_VHF_w2)) { - && (message_words.at(2).contains(qso_partner_base_call) or m_bDoubleClicked or bEU_VHF_w2)) { + && (message_words.at(2).contains(qso_partner_base_call) or m_bDoubleClicked + or bEU_VHF_w2 or (m_QSOProgress==CALLING))) { if(message_words.at(3).contains(grid_regexp) and SpecOp::EU_VHF!=m_config.special_op_id()) { if(SpecOp::NA_VHF==m_config.special_op_id()){ @@ -4478,6 +4582,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } else { // no grid on end of msg QString r=message_words.at (3); if(m_QSOProgress >= ROGER_REPORT && (r=="RRR" || r.toInt()==73 || "RR73" == r)) { + if(m_mode=="FT4" and r=="RR73") m_dateTimeRcvdRR73=QDateTime::currentDateTimeUtc(); if(ui->tabWidget->currentIndex()==1) { gen_msg = 5; if (ui->rbGenMsg->isChecked ()) m_ntx=7; @@ -4494,8 +4599,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie ui->tx3->setText(t); m_bTUmsg=true; } else { -// if(SpecOp::RTTY == m_config.special_op_id()) { - if(false) { + if(SpecOp::RTTY == m_config.special_op_id()) { logQSOTimer.start(0); m_ntx=6; ui->txrb6->setChecked(true); @@ -4507,7 +4611,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } m_QSOProgress = SIGNOFF; } else if((m_QSOProgress >= REPORT - || (m_QSOProgress >= REPLYING && (m_mode=="MSK144" or m_mode=="FT8"))) + || (m_QSOProgress >= REPLYING && + (m_mode=="MSK144" or m_mode=="FT8" or m_mode=="FT4"))) && r.mid(0,1)=="R") { m_ntx=4; m_QSOProgress = ROGERS; @@ -4558,7 +4663,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } m_QSOProgress = SIGNOFF; } - else if (!(m_bAutoReply && m_QSOProgress > CALLING)) { + else if (!(m_bAutoReply && (m_QSOProgress > CALLING))) { if ((message_words.size () > 4 && message_words.at (1).contains (m_baseCall) && message_words.at (4) == "OOO")) { // EME short code report or MSK144/FT8 contest mode reply, send back Tx3 @@ -4690,6 +4795,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie // i.e. compound version of same base call ui->dxCallEntry->setText (hiscall); } + if (hisgrid.contains (grid_regexp)) { if(ui->dxGridEntry->text().mid(0,4) != hisgrid) ui->dxGridEntry->setText(hisgrid); } @@ -4731,7 +4837,10 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } if(m_transmitting) m_restart=true; - if (ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isChecked () && !m_bDoubleClicked) return; + if (ui->cbAutoSeq->isVisible () && ui->cbAutoSeq->isChecked () + && !m_bDoubleClicked && m_mode!="FT4") { + return; + } if(m_config.quick_call()) auto_tx_mode(true); m_bDoubleClicked=false; } @@ -4744,6 +4853,7 @@ int MainWindow::setTxMsg(int n) if(n==3) ui->txrb3->setChecked(true); if(n==4) ui->txrb4->setChecked(true); if(n==5) ui->txrb5->setChecked(true); + if(n==6) ui->txrb6->setChecked(true); if(ui->tabWidget->currentIndex()==1) { m_ntx=7; //### FIX THIS ### m_gen_message_is_cq = false; @@ -4785,12 +4895,17 @@ void MainWindow::genCQMsg () } QString t=ui->tx6->text(); - if((m_mode=="FT8" or m_mode=="MSK144") and SpecOp::NONE != m_config.special_op_id() and - t.split(" ").at(1)==m_config.my_callsign() and stdCall(m_config.my_callsign())) { + if((m_mode=="FT4" or m_mode=="FT8" or m_mode=="MSK144") and + SpecOp::NONE != m_config.special_op_id() and + t.split(" ").at(1)==m_config.my_callsign() and + stdCall(m_config.my_callsign())) { if(SpecOp::NA_VHF == m_config.special_op_id()) t="CQ TEST" + t.mid(2,-1); if(SpecOp::EU_VHF == m_config.special_op_id()) t="CQ TEST" + t.mid(2,-1); if(SpecOp::FIELD_DAY == m_config.special_op_id()) t="CQ FD" + t.mid(2,-1); - if(SpecOp::RTTY == m_config.special_op_id()) t="CQ RU" + t.mid(2,-1); + if(SpecOp::RTTY == m_config.special_op_id()) { + if(m_config.RTTY_Exchange()!="SCC") t="CQ RU" + t.mid(2,-1); + if(m_config.RTTY_Exchange()=="SCC") t="CQ SCC" + t.mid(2,-1); + } ui->tx6->setText(t); } } else { @@ -4821,11 +4936,6 @@ bool MainWindow::stdCall(QString const& w) void MainWindow::genStdMsgs(QString rpt, bool unconditional) { -// Prevent abortQSO from working when a TU; message is already queued -// if(ui->tx3->text().left(4)=="TU; ") { -// return; -// } - genCQMsg (); auto const& hisCall=ui->dxCallEntry->text(); if(!hisCall.size ()) { @@ -4872,7 +4982,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) int n=rpt.toInt(); rpt.sprintf("%+2.2d",n); - if(m_mode=="MSK144" or m_mode=="FT8") { + if(m_mode=="MSK144" or m_mode=="FT8" or m_mode=="FT4") { QString t2,t3; QString sent=rpt; QString rs,rst; @@ -4909,6 +5019,15 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) msgtype(t + sent, ui->tx2); if(sent==rpt) msgtype(t + "R" + sent, ui->tx3); if(sent!=rpt) msgtype(t + "R " + sent, ui->tx3); + if(m_mode=="FT4" and SpecOp::RTTY==m_config.special_op_id()) { + QDateTime now=QDateTime::currentDateTimeUtc(); + int sinceTx3 = m_dateTimeSentTx3.secsTo(now); + int sinceRR73 = m_dateTimeRcvdRR73.secsTo(now); + if(m_bDoubleClicked and (sinceTx3 < 15) and (sinceRR73 < 3)) { + t="TU; " + ui->tx3->text(); + ui->tx3->setText(t); + } + } } if(m_mode=="MSK144" and m_bShMsgs) { @@ -4926,7 +5045,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) } } - if((m_mode!="MSK144" and m_mode!="FT8")) { + if((m_mode!="MSK144" and m_mode!="FT8" and m_mode!="FT4")) { t=t00 + rpt; msgtype(t, ui->tx2); t=t0 + "R" + rpt; @@ -4942,7 +5061,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) } t=t0 + (m_send_RR73 ? "RR73" : "RRR"); - if((m_mode=="MSK144" and !m_bShMsgs) or m_mode=="FT8") { + if((m_mode=="MSK144" and !m_bShMsgs) or m_mode=="FT8" or m_mode=="FT4") { if(!bHisCall and bMyCall) t=hisCall + " <" + my_callsign + "> " + (m_send_RR73 ? "RR73" : "RRR"); if(bHisCall and !bMyCall) t="<" + hisCall + "> " + my_callsign + " " + (m_send_RR73 ? "RR73" : "RRR"); } @@ -4950,7 +5069,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) msgtype(t, ui->tx4); t=t0 + "73"; - if((m_mode=="MSK144" and !m_bShMsgs) or m_mode=="FT8") { + if((m_mode=="MSK144" and !m_bShMsgs) or m_mode=="FT8" or m_mode=="FT4") { if(!bHisCall and bMyCall) t=hisCall + " <" + my_callsign + "> 73"; if(bHisCall and !bMyCall) t="<" + hisCall + "> " + my_callsign + " 73"; } @@ -4966,7 +5085,7 @@ void MainWindow::genStdMsgs(QString rpt, bool unconditional) } } - if(m_mode=="FT8" or m_mode=="MSK144") return; + if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="MSK144") return; if (is_compound) { if (is_type_one) { @@ -5052,10 +5171,9 @@ void MainWindow::TxAgain() void MainWindow::clearDX () { set_dateTimeQSO (-1); - if (m_QSOProgress != CALLING) - { - auto_tx_mode (false); - } + if (m_QSOProgress != CALLING) { + auto_tx_mode (false); + } ui->dxCallEntry->clear (); ui->dxGridEntry->clear (); m_lastCallsign.clear (); @@ -5063,6 +5181,7 @@ void MainWindow::clearDX () m_rptRcvd.clear (); m_qsoStart.clear (); m_qsoStop.clear (); + m_inQSOwith.clear(); genStdMsgs (QString {}); if (ui->tabWidget->currentIndex() == 1) { ui->genMsg->setText(ui->tx6->text()); @@ -5380,15 +5499,10 @@ void MainWindow::on_logQSOButton_clicked() //Log QSO button default: break; } - auto special_op = m_config.special_op_id (); - if (SpecOp::NONE < special_op && special_op < SpecOp::FOX) - { - if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); - } m_logDlg->initLogQSO (m_hisCall, grid, m_modeTx, m_rptSent, m_rptRcvd, m_dateTimeQSOOn, dateTimeQSOOff, m_freqNominal + - ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd, - m_cabrilloLog.data ()); + ui->TxFreqSpinBox->value(), m_noSuffix, m_xSent, m_xRcvd); + m_inQSOwith=""; } void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, QString const& grid @@ -5425,13 +5539,14 @@ void MainWindow::acceptQSO (QDateTime const& QSO_date_off, QString const& call, } } - if (m_config.clear_DX () and SpecOp::HOUND != m_config.special_op_id()) clearDX (); + if(m_config.clear_DX () and SpecOp::HOUND != m_config.special_op_id()) clearDX (); + auto_tx_mode (false); m_dateTimeQSOOn = QDateTime {}; auto special_op = m_config.special_op_id (); - if (SpecOp::NONE < special_op && special_op < SpecOp::FOX) - { - ui->sbSerialNumber->setValue (ui->sbSerialNumber->value () + 1); - } + if (SpecOp::NONE < special_op && special_op < SpecOp::FOX && + m_config.RTTY_Exchange()!="SCC") { + ui->sbSerialNumber->setValue(ui->sbSerialNumber->value() + 1); + } m_xSent.clear (); m_xRcvd.clear (); @@ -5499,13 +5614,64 @@ void MainWindow::displayWidgets(qint64 n) if(i==32) ui->cbCQonly->setVisible(b); j=j>>1; } + ui->pbBestSP->setVisible(m_mode=="FT4"); + b=false; + if(m_mode=="FT4" or m_mode=="FT8") { b=SpecOp::EU_VHF==m_config.special_op_id() or (SpecOp::RTTY==m_config.special_op_id() and - (m_config.RTTY_Exchange()=="#" or m_config.RTTY_Exchange()=="DX")); + (m_config.RTTY_Exchange()=="DX" or m_config.RTTY_Exchange()=="#" or + m_config.RTTY_Exchange()=="SCC")); + } + if(m_mode=="MSK144") b=SpecOp::EU_VHF==m_config.special_op_id(); ui->sbSerialNumber->setVisible(b); m_lastCallsign.clear (); // ensures Tx5 is updated for new modes genStdMsgs (m_rpt, true); } +void MainWindow::on_actionFT4_triggered() +{ + m_mode="FT4"; + m_modeTx="FT4"; + m_TRperiod=7.5; + bool bVHF=m_config.enable_VHF_features(); + m_bFast9=false; + m_bFastMode=false; + WSPR_config(false); + switch_mode (Modes::FT4); + m_nsps=6912; + m_FFTSize = m_nsps/2; + Q_EMIT FFTSize (m_FFTSize); + m_hsymStop=21; + setup_status_bar (bVHF); + m_toneSpacing=12000.0/576.0; + ui->actionFT4->setChecked(true); + m_wideGraph->setMode(m_mode); + m_wideGraph->setModeTx(m_modeTx); + m_send_RR73=true; + VHF_features_enabled(bVHF); +// ui->cbAutoSeq->setChecked(false); + m_fastGraph->hide(); + m_wideGraph->show(); + ui->decodedTextLabel2->setText(" UTC dB DT Freq Message"); + m_wideGraph->setPeriod(m_TRperiod,m_nsps); + m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe + m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe + ui->label_7->setText("Rx Frequency"); + ui->label_6->setText("Band Activity"); + ui->decodedTextLabel->setText( " UTC dB DT Freq Message"); + displayWidgets(nWidgets("111010000100111000010000000110001")); + ui->txrb2->setEnabled(true); + ui->txrb4->setEnabled(true); + ui->txrb5->setEnabled(true); + ui->txrb6->setEnabled(true); + ui->txb2->setEnabled(true); + ui->txb4->setEnabled(true); + ui->txb5->setEnabled(true); + ui->txb6->setEnabled(true); + ui->txFirstCheckBox->setEnabled(true); + chkFT4(); + statusChanged(); +} + void MainWindow::on_actionFT8_triggered() { m_mode="FT8"; @@ -5526,7 +5692,7 @@ void MainWindow::on_actionFT8_triggered() m_wideGraph->setModeTx(m_modeTx); VHF_features_enabled(bVHF); ui->cbAutoSeq->setChecked(true); - m_TRperiod=15; + m_TRperiod=15.0; m_fastGraph->hide(); m_wideGraph->show(); ui->decodedTextLabel2->setText(" UTC dB DT Freq Message"); @@ -5608,8 +5774,6 @@ void MainWindow::on_actionFT8_triggered() statusChanged(); } - - void MainWindow::on_actionJT4_triggered() { m_mode="JT4"; @@ -5617,7 +5781,7 @@ void MainWindow::on_actionJT4_triggered() WSPR_config(false); switch_mode (Modes::JT4); m_modeTx="JT4"; - m_TRperiod=60; + m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; //For symspec only @@ -5690,7 +5854,7 @@ void MainWindow::on_actionJT9_triggered() ui->decodedTextLabel2->setText("UTC dB T Freq Message"); } else { ui->cbAutoSeq->setChecked(false); - m_TRperiod=60; + m_TRperiod=60.0; ui->decodedTextLabel->setText("UTC dB DT Freq Message"); ui->decodedTextLabel2->setText("UTC dB DT Freq Message"); } @@ -5719,7 +5883,7 @@ void MainWindow::on_actionJT9_JT65_triggered() m_modeTx="JT9"; } m_nSubMode=0; //Dual-mode always means JT9 and JT65A - m_TRperiod=60; + m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; @@ -5761,7 +5925,7 @@ void MainWindow::on_actionJT65_triggered() WSPR_config(false); switch_mode (Modes::JT65); if(m_modeTx!="JT65") on_pbTxMode_clicked(); - m_TRperiod=60; + m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; //For symspec only @@ -5819,6 +5983,8 @@ void MainWindow::on_actionQRA64_triggered() ui->sbSubmode->setValue(m_nSubMode); ui->actionInclude_averaging->setVisible (false); ui->actionInclude_correlation->setVisible (false); + ui->RxFreqSpinBox->setValue(1000); + ui->TxFreqSpinBox->setValue(1000); QString fname {QDir::toNativeSeparators(m_config.temp_dir ().absoluteFilePath ("red.dat"))}; m_wideGraph->setRedFile(fname); displayWidgets(nWidgets("111110010010111110000000001000000")); @@ -5937,7 +6103,7 @@ void MainWindow::on_actionWSPR_triggered() WSPR_config(true); switch_mode (Modes::WSPR); m_modeTx="WSPR"; - m_TRperiod=120; + m_TRperiod=120.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; //For symspec only @@ -5965,7 +6131,7 @@ void MainWindow::on_actionWSPR_LF_triggered() m_mode="WSPR-LF"; switch_mode (Modes::WSPR); m_modeTx="WSPR-LF"; - m_TRperiod=240; + m_TRperiod=240.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_hsymStop=813; @@ -5981,7 +6147,7 @@ void MainWindow::on_actionEcho_triggered() on_actionJT4_triggered(); m_mode="Echo"; ui->actionEcho->setChecked(true); - m_TRperiod=3; + m_TRperiod=3.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; //For symspec only @@ -6177,16 +6343,14 @@ void MainWindow::on_reset_cabrillo_log_action_triggered () "They will be kept in the ADIF log file but will not be available " "for export in your Cabrillo log."))) { - ui->sbSerialNumber->setValue (1); - if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); - m_cabrilloLog->reset (); + if(m_config.RTTY_Exchange()!="SCC") ui->sbSerialNumber->setValue(1); + m_logBook.contest_log ()->reset (); } } void MainWindow::on_actionExport_Cabrillo_log_triggered() { - if (!m_cabrilloLog) m_cabrilloLog.reset (new CabrilloLog {&m_config}); - if (QDialog::Accepted == ExportCabrillo {m_settings, &m_config, m_cabrilloLog.data ()}.exec()) + if (QDialog::Accepted == ExportCabrillo {m_settings, &m_config, m_logBook.contest_log ()}.exec()) { MessageBox::information_message (this, tr ("Cabrillo Log saved")); } @@ -6260,7 +6424,6 @@ void MainWindow::on_bandComboBox_activated (int index) void MainWindow::band_changed (Frequency f) { -// bool monitor_off=!m_monitoring; // Set the attenuation value if options are checked QString curBand = ui->bandComboBox->currentText(); if (m_config.pwrBandTxMemory() && !m_tune) { @@ -6296,7 +6459,6 @@ void MainWindow::band_changed (Frequency f) if(r<0.9 or r>1.1) m_bVHFwarned=false; setRig (f); setXIT (ui->TxFreqSpinBox->value ()); -// if(monitor_off) monitor(false); } } @@ -6613,18 +6775,17 @@ void MainWindow::setFreq4(int rxFreq, int txFreq) void MainWindow::handle_transceiver_update (Transceiver::TransceiverState const& s) { - // qDebug () << "MainWindow::handle_transceiver_update:" << s; Transceiver::TransceiverState old_state {m_rigState}; //transmitDisplay (s.ptt ()); - 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 - { - ptt1Timer.start(1000 * m_config.txDelay ()); //Start-of-transmission sequencer delay - } - m_tx_when_ready = false; + 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_rigState = s; auto old_freqNominal = m_freqNominal; if (!old_freqNominal) @@ -6763,7 +6924,8 @@ void MainWindow::transmit (double snr) } if (m_modeTx == "FT8") { - toneSpacing=12000.0/1920.0; +// toneSpacing=12000.0/1920.0; + toneSpacing=-3; if(m_config.x2ToneSpacing()) toneSpacing=2*12000.0/1920.0; if(m_config.x4ToneSpacing()) toneSpacing=4*12000.0/1920.0; if(SpecOp::FOX==m_config.special_op_id() and !m_tune) toneSpacing=-1; @@ -6773,6 +6935,15 @@ void MainWindow::transmit (double snr) true, false, snr, m_TRperiod); } + if (m_modeTx == "FT4") { + m_dateTimeSentTx3=QDateTime::currentDateTimeUtc(); + toneSpacing=-2.0; //Transmit a pre-computed, filtered waveform. + Q_EMIT sendMessage (NUM_FT4_SYMBOLS, + 576.0, ui->TxFreqSpinBox->value() - m_XIT, + toneSpacing, m_soundOutput, m_config.audio_output_channel(), + true, false, snr, m_TRperiod); + } + if (m_modeTx == "QRA64") { if(m_nSubMode==0) toneSpacing=12000.0/6912.0; if(m_nSubMode==1) toneSpacing=2*12000.0/6912.0; @@ -6998,6 +7169,7 @@ void MainWindow::transmitDisplay (bool transmitting) void MainWindow::on_sbFtol_valueChanged(int value) { m_wideGraph->setTol (value); + statusUpdate (); } void::MainWindow::VHF_features_enabled(bool b) @@ -7035,6 +7207,7 @@ void MainWindow::on_sbTR_valueChanged(int value) if(m_transmitting) { on_stopTxButton_clicked(); } + statusUpdate (); } QChar MainWindow::current_submode () const @@ -7071,7 +7244,7 @@ void MainWindow::on_sbSubmode_valueChanged(int n) on_cbFast9_clicked(false); ui->cbFast9->setEnabled(false); ui->sbTR->setVisible(false); - m_TRperiod=60; + m_TRperiod=60.0; } else { ui->cbFast9->setEnabled(true); } @@ -7093,9 +7266,9 @@ void MainWindow::on_cbFast9_clicked(bool b) if(b) { m_TRperiod = ui->sbTR->value (); } else { - m_TRperiod=60; + m_TRperiod=60.0; } - progressBar.setMaximum(m_TRperiod); + progressBar.setMaximum(int(m_TRperiod)); m_wideGraph->setPeriod(m_TRperiod,m_nsps); fast_config(b); statusChanged (); @@ -7136,13 +7309,9 @@ void MainWindow::replyToCQ (QTime time, qint32 snr, float delta_time, quint32 de , QString const& mode, QString const& message_text , bool /*low_confidence*/, quint8 modifiers) { - if (!m_config.accept_udp_requests ()) - { - return; - } - QString format_string {"%1 %2 %3 %4 %5 %6"}; - auto const& time_string = time.toString ("~" == mode || "&" == mode ? "hhmmss" : "hhmm"); + auto const& time_string = time.toString ("~" == mode || "&" == mode + || "+" == mode ? "hhmmss" : "hhmm"); auto message_line = format_string .arg (time_string) .arg (snr, 3) @@ -7374,8 +7543,8 @@ void MainWindow::p1ReadFromStdout() //p1readFromStdout if(grid!="") { double utch=0.0; int nAz,nEl,nDmiles,nDkm,nHotAz,nHotABetter; - azdist_(const_cast (m_config.my_grid ().toLatin1().constData()), - const_cast (grid.toLatin1().constData()),&utch, + azdist_(const_cast ((m_config.my_grid () + " ").left (6).toLatin1 ().constData ()), + const_cast ((grid + " ").left (6).toLatin1 ().constData ()),&utch, &nAz,&nEl,&nDmiles,&nDkm,&nHotAz,&nHotABetter,6,6); QString t1; if(m_config.miles()) { @@ -7638,7 +7807,7 @@ void MainWindow::setRig (Frequency f) void MainWindow::fastPick(int x0, int x1, int y) { float pixPerSecond=12000.0/512.0; - if(m_TRperiod<30) pixPerSecond=12000.0/256.0; + if(m_TRperiod<30.0) pixPerSecond=12000.0/256.0; if(m_mode!="ISCAT" and m_mode!="MSK144") return; if(!m_decoderBusy) { dec_data.params.newdat=0; @@ -7708,8 +7877,18 @@ void MainWindow::on_cbCQTx_toggled(bool b) void MainWindow::statusUpdate () const { - if (!ui) return; + if (!ui || m_block_udp_status_updates) return; auto submode = current_submode (); + auto ftol = ui->sbFtol->value (); + if (!(ui->sbFtol->isVisible () && ui->sbFtol->isEnabled ())) + { + ftol = quint32_max; + } + auto tr_period = ui->sbTR->value (); + if (!(ui->sbTR->isVisible () && ui->sbTR->isEnabled ())) + { + tr_period = quint32_max; + } m_messageClient->status_update (m_freqNominal, m_mode, m_hisCall, QString::number (ui->rptSpinBox->value ()), m_modeTx, ui->autoButton->isChecked (), @@ -7718,7 +7897,8 @@ void MainWindow::statusUpdate () const m_config.my_callsign (), m_config.my_grid (), m_hisGrid, m_tx_watchdog, submode != QChar::Null ? QString {submode} : QString {}, m_bFastMode, - static_cast (m_config.special_op_id ())); + static_cast (m_config.special_op_id ()), + ftol, tr_period, m_multi_settings->configuration_name ()); } void MainWindow::childEvent (QChildEvent * e) @@ -7824,7 +8004,7 @@ void MainWindow::on_cbFirst_toggled(bool b) void MainWindow::on_cbAutoSeq_toggled(bool b) { if(!b) ui->cbFirst->setChecked(false); - ui->cbFirst->setVisible((m_mode=="FT8") and b); + ui->cbFirst->setVisible((m_mode=="FT8" or m_mode=="FT4") and b); } void MainWindow::on_measure_check_box_stateChanged (int state) @@ -7839,7 +8019,7 @@ void MainWindow::write_transmit_entry (QString const& file_name) { QTextStream out(&f); auto time = QDateTime::currentDateTimeUtc (); - time = time.addSecs (-(time.time ().second () % m_TRperiod)); + time = time.addSecs (-fmod(double(time.time().second()),m_TRperiod)); out << time.toString("yyMMdd_hhmmss") << " Transmitting " << qSetRealNumberPrecision (12) << (m_freqNominal / 1.e6) << " MHz " << m_modeTx @@ -8079,7 +8259,7 @@ void MainWindow::houndCallers() if(!ui->textBrowser4->toPlainText().contains(paddedHoundCall)) { if(m_loggedByFox[houndCall].contains(m_lastBand)) continue; //already logged on this band if(m_foxQSO.contains(houndCall)) continue; //still in the QSO map - auto const& entity = m_logBook.countries ().lookup (houndCall); + auto const& entity = m_logBook.countries ()->lookup (houndCall); auto const& continent = AD1CCty::continent (entity.continent); //If we are using a directed CQ, ignore Hound calls that do not comply. @@ -8260,9 +8440,8 @@ list2Done: m_hisGrid=m_foxQSO[hc1].grid; m_rptSent=m_foxQSO[hc1].sent; m_rptRcvd=m_foxQSO[hc1].rcvd; - if (!m_foxLog) m_foxLog.reset (new FoxLog {&m_config}); if (!m_foxLogWindow) on_fox_log_action_triggered (); - if (m_foxLog->add_QSO (QSO_time, m_hisCall, m_hisGrid, m_rptSent, m_rptRcvd, m_lastBand)) + if (m_logBook.fox_log ()->add_QSO (QSO_time, m_hisCall, m_hisGrid, m_rptSent, m_rptRcvd, m_lastBand)) { writeFoxQSO (QString {" Log: %1 %2 %3 %4 %5"}.arg (m_hisCall).arg (m_hisGrid) .arg (m_rptSent).arg (m_rptRcvd).arg (m_lastBand)); @@ -8480,24 +8659,44 @@ void MainWindow::write_all(QString txRx, QString message) { QString line; QString t; - QString msg=message.mid(6,-1); + QString msg; + QString mode_string; + + if (message[4]==' ') { + msg=message.mid(4,-1); + } else { + msg=message.mid(6,-1); + } + + if (message[19]=='#') { + mode_string="JT65 "; + } else if (message[19]=='@') { + mode_string="JT9 "; + } else { + mode_string=m_mode.leftJustified(6,' '); + } + msg=msg.mid(0,15) + msg.mid(18,-1); t.sprintf("%5d",ui->TxFreqSpinBox->value()); - if(txRx=="Tx") msg=" 0 0.0" + t + " " + message; + if (txRx=="Tx") msg=" 0 0.0" + t + " " + message; auto time = QDateTime::currentDateTimeUtc (); - time = time.addSecs (-(time.time ().second () % m_TRperiod)); + time = time.addSecs(-fmod(double(time.time().second()),m_TRperiod)); t.sprintf("%10.3f ",m_freqNominal/1.e6); - if(m_diskData) { - line=m_fileDateTime + t + txRx + " " + m_mode.leftJustified(6,' ') + msg; + if (m_diskData) { + if (m_fileDateTime.size()==11) { + line=m_fileDateTime + " " + t + txRx + " " + mode_string + msg; + } else { + line=m_fileDateTime + t + txRx + " " + mode_string + msg; + } } else { - line=time.toString("yyMMdd_hhmmss") + t + txRx + " " + m_mode.leftJustified(6,' ') + msg; + line=time.toString("yyMMdd_hhmmss") + t + txRx + " " + mode_string + msg; } QString file_name="ALL.TXT"; - if(m_mode=="WSPR") file_name="ALL_WSPR.TXT"; + if (m_mode=="WSPR") file_name="ALL_WSPR.TXT"; QFile f{m_config.writeable_data_dir().absoluteFilePath(file_name)}; - if(f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { + if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) { QTextStream out(&f); out << line << endl; f.close(); @@ -8508,3 +8707,112 @@ void MainWindow::write_all(QString txRx, QString message) MessageBox::warning_message(this, tr ("Log File Error"), message2); }); } } + +void MainWindow::chkFT4() +{ + if(m_mode!="FT4") return; + ui->cbAutoSeq->setEnabled(true); + ui->cbFirst->setVisible(true); + ui->cbFirst->setEnabled(true); + ui->labDXped->setVisible(m_config.special_op_id()!=SpecOp::NONE); + ui->cbFirst->setVisible(ui->cbAutoSeq->isChecked()); + + if (SpecOp::NONE < m_config.special_op_id () && SpecOp::FOX > m_config.special_op_id ()) { + QString t0=""; + if(SpecOp::NA_VHF==m_config.special_op_id()) t0+="NA VHF"; + if(SpecOp::EU_VHF==m_config.special_op_id()) t0+="EU VHF"; + if(SpecOp::FIELD_DAY==m_config.special_op_id()) t0+="Field Day"; + if(SpecOp::RTTY==m_config.special_op_id()) t0+="RTTY"; + if(t0=="") { + ui->labDXped->setVisible(false); + } else { + ui->labDXped->setVisible(true); + ui->labDXped->setText(t0); + } + on_contest_log_action_triggered(); + } +} + +void MainWindow::on_pbBestSP_clicked() +{ + m_bBestSPArmed = !m_bBestSPArmed; + if(m_bBestSPArmed and !m_transmitting) ui->pbBestSP->setStyleSheet ("QPushButton{color:red}"); + if(!m_bBestSPArmed) ui->pbBestSP->setStyleSheet (""); + if(m_bBestSPArmed) m_dateTimeBestSP=QDateTime::currentDateTimeUtc(); +} + +void MainWindow::set_mode (QString const& mode) +{ + if ("FT4" == mode) on_actionFT4_triggered (); + else if ("FT8" == mode) on_actionFT8_triggered (); + else if ("JT4" == mode) on_actionJT4_triggered (); + else if ("JT9" == mode) on_actionJT9_triggered (); + else if ("JT9+JT65" == mode) on_actionJT9_JT65_triggered (); + else if ("JT65" == mode) on_actionJT65_triggered (); + else if ("QRA64" == mode) on_actionQRA64_triggered (); + else if ("FreqCal" == mode) on_actionFreqCal_triggered (); + else if ("ISCAT" == mode) on_actionISCAT_triggered (); + else if ("MSK144" == mode) on_actionMSK144_triggered (); + else if ("WSPR" == mode) on_actionWSPR_triggered (); + else if ("WSPR-LF" == mode) on_actionWSPR_LF_triggered (); + else if ("Echo" == mode) on_actionEcho_triggered (); +} + +void MainWindow::remote_configure (QString const& mode, quint32 frequency_tolerance + , QString const& submode, bool fast_mode, quint32 tr_period, quint32 rx_df + , QString const& dx_call, QString const& dx_grid, bool generate_messages) +{ + if (mode.size ()) + { + set_mode (mode); + } + if (frequency_tolerance != quint32_max && ui->sbFtol->isVisible ()) + { + ui->sbFtol->setValue (frequency_tolerance); + } + if (submode.size () && ui->sbSubmode->isVisible ()) + { + ui->sbSubmode->setValue (submode.toUpper ().at (0).toLatin1 () - 'A'); + } + if (ui->cbFast9->isVisible () && ui->cbFast9->isChecked () != fast_mode) + { + ui->cbFast9->click (); + } + if (tr_period != quint32_max && ui->sbTR->isVisible ()) + { + ui->sbTR->setValue (tr_period); + ui->sbTR->interpretText (); + } + if (rx_df != quint32_max && ui->RxFreqSpinBox->isVisible ()) + { + m_block_udp_status_updates = true; + ui->RxFreqSpinBox->setValue (rx_df); + ui->RxFreqSpinBox->interpretText (); + m_block_udp_status_updates = false; + } + if (dx_call.size () && ui->dxCallEntry->isVisible ()) + { + ui->dxCallEntry->setText (dx_call); + } + if (dx_grid.size () && ui->dxGridEntry->isVisible ()) + { + ui->dxGridEntry->setText (dx_grid); + } + if (generate_messages && ui->genStdMsgsPushButton->isVisible ()) + { + ui->genStdMsgsPushButton->click (); + } + if (m_config.udpWindowToFront ()) + { + show (); + raise (); + activateWindow (); + } + if (m_config.udpWindowRestore () && isMinimized ()) + { + showNormal (); + raise (); + } + tx_watchdog (false); + QApplication::alert (this); +} diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index acabffe7f..514dbb30a 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -46,9 +46,11 @@ #define NUM_MSK144_SYMBOLS 144 //s8 + d48 + s8 + d80 #define NUM_QRA64_SYMBOLS 84 //63 data + 21 sync #define NUM_FT8_SYMBOLS 79 +#define NUM_FT4_SYMBOLS 105 #define NUM_CW_SYMBOLS 250 #define TX_SAMPLE_RATE 48000 #define N_WIDGETS 33 +#define NRING 3456000 extern int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols extern int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID @@ -70,9 +72,7 @@ class WideGraph; class LogQSO; class Transceiver; class MessageAveraging; -class FoxLog; class FoxLogWindow; -class CabrilloLog; class CabrilloLogWindow; class ColorHighlighting; class MessageClient; @@ -200,6 +200,7 @@ private slots: void on_actionJT65_triggered(); void on_actionJT9_JT65_triggered(); void on_actionJT4_triggered(); + void on_actionFT4_triggered(); void on_actionFT8_triggered(); void on_TxFreqSpinBox_valueChanged(int arg1); void on_actionSave_decoded_triggered(); @@ -309,8 +310,12 @@ private slots: void on_comboBoxHoundSort_activated (int index); void not_GA_warning_message (); void checkMSK144ContestType(); + void on_pbBestSP_clicked(); int setTxMsg(int n); bool stdCall(QString const& w); + void remote_configure (QString const& mode, quint32 frequency_tolerance, QString const& submode + , bool fast_mode, quint32 tr_period, quint32 rx_df, QString const& dx_call + , QString const& dx_grid, bool generate_messages); private: Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo, @@ -337,12 +342,14 @@ private: Q_SIGNAL void toggleShorthand () const; private: + void set_mode (QString const& mode); void astroUpdate (); void writeAllTxt(QString message); void auto_sequence (DecodedText const& message, unsigned start_tolerance, unsigned stop_tolerance); void hideMenus(bool b); void foxTest(); void setColorHighlighting(); + void chkFT4(); NetworkAccessManager m_network_manager; bool m_valid; @@ -354,8 +361,8 @@ private: QSettings * m_settings; QScopedPointer ui; - LogBook m_logBook; // must be before Configuration construction Configuration m_config; + LogBook m_logBook; // must be after Configuration construction WSPRBandHopping m_WSPR_band_hopping; bool m_WSPR_tx_next; MessageBox m_rigErrorMessageBox; @@ -371,9 +378,7 @@ private: QScopedPointer m_prefixes; QScopedPointer m_mouseCmnds; QScopedPointer m_msgAvgWidget; - QScopedPointer m_foxLog; QScopedPointer m_foxLogWindow; - QScopedPointer m_cabrilloLog; QScopedPointer m_contestLogWindow; QScopedPointer m_colorHighlighting; Transceiver::TransceiverState m_rigState; @@ -401,6 +406,7 @@ private: double m_s6; double m_tRemaining; + double m_TRperiod; float m_DTtol; float m_t0; @@ -423,7 +429,6 @@ private: qint32 m_ntr; qint32 m_tx; qint32 m_hsym; - qint32 m_TRperiod; qint32 m_nsps; qint32 m_hsymStop; qint32 m_inGain; @@ -461,6 +466,7 @@ private: qint32 m_tFoxTxSinceCQ=999; //Fox Tx cycles since most recent CQ qint32 m_nFoxFreq; //Audio freq at which Hound received a call from Fox qint32 m_nSentFoxRrpt=0; //Serial number for next R+rpt Hound will send to Fox + qint32 m_kin0=0; bool m_btxok; //True if OK to transmit bool m_diskData; @@ -515,6 +521,7 @@ private: bool m_bCheckedContest; bool m_bWarnedSplit=false; bool m_bTUmsg; + bool m_bBestSPArmed=false; enum { @@ -609,6 +616,8 @@ private: QString m_nextCall; QString m_nextGrid; QString m_fileDateTime; + QString m_inQSOwith; + QString m_BestCQpriority; QSet m_pfx; QSet m_sfx; @@ -627,12 +636,24 @@ private: QMap m_foxQSO; //Key = HoundCall, value = parameters for QSO in progress QMap m_loggedByFox; //Key = HoundCall, value = logged band + struct FixupQSO //Info for fixing Fox's log from file "FoxQSO.txt" + { + QString grid; //Hound's declared locator + QString sent; //Report sent to Hound + QString rcvd; //Report received from Hound + QDateTime QSO_time; + }; + QMap m_fixupQSO; //Key = HoundCall, value = info for QSO in progress + QQueue m_houndQueue; //Selected Hounds available for starting a QSO QQueue m_foxQSOinProgress; //QSOs in progress: Fox has sent a report QQueue m_foxRateQueue; QDateTime m_dateTimeQSOOn; QDateTime m_dateTimeLastTX; + QDateTime m_dateTimeSentTx3; + QDateTime m_dateTimeRcvdRR73; + QDateTime m_dateTimeBestSP; QSharedMemory *mem_jt9; QString m_QSOText; @@ -663,6 +684,7 @@ private: QHash m_pwrBandTuneMemory; // Remembers power level by band for tuning QByteArray m_geometryNoControls; QVector m_phaseEqCoefficients; + bool m_block_udp_status_updates; //---------------------------------------------------- private functions void readSettings(); @@ -709,7 +731,7 @@ private: QString save_wave_file (QString const& name , short const * data - , int seconds + , int samples , QString const& my_callsign , QString const& my_grid , QString const& mode diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 4e39e6d6c..75be401d0 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -340,7 +340,7 @@ - <html><head/><body><p>Enter this QSO in log</p></body></html> + Enter this QSO in log Log &QSO @@ -372,7 +372,7 @@ - <html><head/><body><p>Toggle monitoring On/Off</p></body></html> + Toggle monitoring On/Off QPushButton:checked { @@ -407,6 +407,9 @@ <html><head/><body><p>Erase right window. Double-click to erase both windows.</p></body></html> + + Erase right window. Double-click to erase both windows. + &Erase @@ -420,6 +423,9 @@ <html><head/><body><p>Clear the accumulating message average.</p></body></html> + + Clear the accumulating message average. + Clear Avg @@ -436,6 +442,9 @@ <html><head/><body><p>Decode most recent Rx period at QSO Frequency</p></body></html> + + Decode most recent Rx period at QSO Frequency + QPushButton:checked { background-color: cyan; @@ -466,6 +475,9 @@ <html><head/><body><p>Toggle Auto-Tx On/Off</p></body></html> + + Toggle Auto-Tx On/Off + QPushButton:checked { background-color: red; @@ -506,6 +518,9 @@ <html><head/><body><p>Toggle a pure Tx tone On/Off</p></body></html> + + Toggle a pure Tx tone On/Off + QPushButton:checked { background-color: red; @@ -590,6 +605,15 @@ QLabel[oob="true"] { <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> + + Rx Signal + + + 30dB recommended when only noise present +Green when good +Red when clipping may occur +Yellow when too low + QFrame::Panel @@ -706,6 +730,9 @@ QLabel[oob="true"] { 2 + + dxCallEntry + @@ -795,6 +822,9 @@ QLabel[oob="true"] { 2 + + dxGridEntry + @@ -883,6 +913,9 @@ QLabel[oob="true"] { <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> + + If orange or red there has been a rig control failure, click to reset and read the dial frequency. S implies split mode. + QPushButton { font-family: helvetica; @@ -947,6 +980,12 @@ QPushButton[state="ok"] { <html><head/><body><p>Select operating band or enter frequency in MHz or enter kHz increment followed by k.</p></body></html> + + Frequncy entry + + + Select operating band or enter frequency in MHz or enter kHz increment followed by k. + true @@ -1038,6 +1077,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Check to keep Tx frequency fixed when double-clicking on decoded text.</p></body></html> + + Check to keep Tx frequency fixed when double-clicking on decoded text. + Hold Tx Freq @@ -1155,6 +1197,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> + + Synchronizing threshold. Lower numbers accept weaker sync signals. + Qt::AlignCenter @@ -1179,6 +1224,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Check to use short-format messages.</p></body></html> + + Check to use short-format messages. + Sh @@ -1189,6 +1237,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Check to enable JT9 fast modes</p></body></html> + + Check to enable JT9 fast modes + Fast @@ -1199,6 +1250,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Check to enable automatic sequencing of Tx messages based on received messages.</p></body></html> + + Check to enable automatic sequencing of Tx messages based on received messages. + Auto Seq @@ -1209,6 +1263,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Check to call the first decoded responder to my CQ.</p></body></html> + + Check to call the first decoded responder to my CQ. + Call 1st @@ -1234,6 +1291,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences.</p></body></html> + + Check to Tx in even-numbered minutes or sequences, starting at 0; uncheck for odd sequences. + Tx even/1st @@ -1249,6 +1309,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Frequency to call CQ on in kHz above the current MHz</p></body></html> + + Frequency to call CQ on in kHz above the current MHz + Tx CQ @@ -1271,6 +1334,10 @@ QPushButton[state="ok"] { <html><head/><body><p>Check this to call CQ on the &quot;Tx CQ&quot; frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on.</p><p>Not available to nonstandard callsign holders.</p></body></html> + + Check this to call CQ on the "Tx CQ" frequency. Rx will be on the current frequency and the CQ message wiill include the current Rx frequency so callers know which frequency to reply on. +Not available to nonstandard callsign holders. + @@ -1290,6 +1357,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> + + Submode determines tone spacing; A is narrowest. + Qt::AlignCenter @@ -1333,16 +1403,45 @@ QPushButton[state="ok"] { <html><head/><body><p>Check to monitor Sh messages.</p></body></html> + + Check to monitor Sh messages. + SWL + + + + QPushButton:checked { + background-color: red; + border-style: outset; + border-width: 1px; + border-radius: 5px; + border-color: black; + min-width: 5em; + padding: 3px; +} + + + Best S+P + + + true + + + <html><head/><body><p>Check this to start recording calibration data.<br/>While measuring calibration correction is disabled.<br/>When not checked you can view the calibration results.</p></body></html> + + Check this to start recording calibration data. +While measuring calibration correction is disabled. +When not checked you can view the calibration results. + Measure @@ -1355,6 +1454,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Signal report: Signal-to-noise ratio in 2500 Hz reference bandwidth (dB).</p></body></html> + + Signal report: Signal-to-noise ratio in 2500 Hz reference bandwidth (dB). + Qt::AlignCenter @@ -1377,6 +1479,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Tx/Rx or Frequency calibration sequence length</p></body></html> + + Tx/Rx or Frequency calibration sequence length + Qt::AlignCenter @@ -1475,6 +1580,9 @@ QPushButton[state="ok"] { <html><head/><body><p>Double-click on another caller to queue that call for your next QSO.</p></body></html> + + Double-click on another caller to queue that call for your next QSO. + Next Call @@ -1530,6 +1638,10 @@ QPushButton[state="ok"] { <html><head/><body><p>Send this message in next Tx interval</p><p>Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders)</p></body></html> + + Send this message in next Tx interval +Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders) + margin-left: 10%; margin-right: 0% @@ -1565,6 +1677,10 @@ QPushButton[state="ok"] { <html><head/><body><p>Switch to this Tx message NOW</p><p>Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders)</p></body></html> + + Switch to this Tx message NOW +Double click to toggle the use of the Tx1 message to start a QSO with a station (not allowed for type 1 compound call holders) + Qt::LeftToRight @@ -1606,6 +1722,10 @@ QPushButton[state="ok"] { <html><head/><body><p>Send this message in next Tx interval</p><p>Double-click to reset to the standard 73 message</p></body></html> + + Send this message in next Tx interval +Double-click to reset to the standard 73 message + margin-left: 10%; margin-right: 0% @@ -1654,6 +1774,11 @@ QPushButton[state="ok"] { <html><head/><body><p>Send this message in next Tx interval</p><p>Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type 2 compound call holders)</p><p>RR73 messages should only be used when you are reasonably confident that no message repetitions will be required</p></body></html> + + Send this message in next Tx interval +Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type 2 compound call holders) +RR73 messages should only be used when you are reasonably confident that no message repetitions will be required + margin-left: 10%; margin-right: 0% @@ -1670,6 +1795,11 @@ QPushButton[state="ok"] { <html><head/><body><p>Switch to this Tx message NOW</p><p>Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type2 compound call holders)</p><p>RR73 messages should only be used when you are reasonably confident that no message repetitions will be required</p></body></html> + + Switch to this Tx message NOW +Double-click to toggle between RRR and RR73 messages in Tx4 (not allowed for type2 compound call holders) +RR73 messages should only be used when you are reasonably confident that no message repetitions will be required + padding-left: 15%; padding-right: 15%; padding-top: 3%; padding-bottom: 3% @@ -1686,6 +1816,10 @@ QPushButton[state="ok"] { <html><head/><body><p>Switch to this Tx message NOW</p><p>Double-click to reset to the standard 73 message</p></body></html> + + Switch to this Tx message NOW +Double-click to reset to the standard 73 message + padding-left: 15%; padding-right: 15%; padding-top: 3%; padding-bottom: 3% @@ -2503,6 +2637,9 @@ list. The list can be maintained in Settings (F2). <html><head/><body><p>6 digit locators cause 2 different mesages to be sent, the second contains the full locator but only a hashed callsign, other stations must have decoded the first once before they can decode your call in the second. Check this option to only send 4 digit locators if it will avoid the two message protocol.</p></body></html> + + 6 digit locators cause 2 different mesages to be sent, the second contains the full locator but only a hashed callsign, other stations must have decoded the first once before they can decode your call in the second. Check this option to only send 4 digit locators if it will avoid the two message protocol. + Prefer type 1 messages @@ -2705,6 +2842,7 @@ list. The list can be maintained in Settings (F2). Mode + @@ -2773,9 +2911,6 @@ list. The list can be maintained in Settings (F2). About WSJT-X - - Ctrl+F1 - @@ -2794,9 +2929,6 @@ list. The list can be maintained in Settings (F2). Open next in directory - - F6 - @@ -3290,14 +3422,6 @@ list. The list can be maintained in Settings (F2). Fox log - - - Reset Fox log ... - - - <html><head/><body><p>Ths will erase the file FoxQSO.txt and delete the Fox log file which is used for dupe detection.</p></body></html> - - FT8 DXpedition Mode User Guide @@ -3338,6 +3462,14 @@ list. The list can be maintained in Settings (F2). Erase WSPR hashtable + + + true + + + FT4 + + diff --git a/widgets/messageaveraging.cpp b/widgets/messageaveraging.cpp index fce022842..21f7b07ca 100644 --- a/widgets/messageaveraging.cpp +++ b/widgets/messageaveraging.cpp @@ -8,6 +8,8 @@ #include "qt_helpers.hpp" #include "ui_messageaveraging.h" +#include "moc_messageaveraging.cpp" + MessageAveraging::MessageAveraging(QSettings * settings, QFont const& font, QWidget *parent) : QWidget(parent), settings_ {settings}, diff --git a/widgets/messageaveraging.h b/widgets/messageaveraging.h index 4a8556b24..a5ed7b54d 100644 --- a/widgets/messageaveraging.h +++ b/widgets/messageaveraging.h @@ -14,6 +14,8 @@ namespace Ui { class MessageAveraging : public QWidget { + Q_OBJECT + public: explicit MessageAveraging(QSettings *, QFont const&, QWidget * parent = 0); ~MessageAveraging(); diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index 761dae08d..badeff57b 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -123,6 +123,7 @@ void CPlotter::paintEvent(QPaintEvent *) // paint void CPlotter::draw(float swide[], bool bScroll, bool bRed) { + if (!m_TRperiod) return; // not ready to plot yet int j,j0; static int ktop=0; float y,y2,ymin; @@ -166,7 +167,7 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed) ymin=1.e30; if(swide[0]>1.e29 and swide[0]< 1.5e30) painter1.setPen(Qt::green); - if(swide[0]>1.4e30) painter1.setPen(Qt::yellow); + if(swide[0]>1.4e30) painter1.setPen(Qt::red); if(!m_bReplot) { m_j=0; int irow=-1; @@ -235,13 +236,14 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed) if(m_bReplot) return; if(swide[0]>1.0e29) m_line=0; + if(m_mode=="FT4" and m_line==34) m_line=0; if(m_line == painter1.fontMetrics ().height ()) { painter1.setPen(Qt::white); QString t; qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - int n=(ms/1000) % m_TRperiod; + int n = fmod(0.001*ms,m_TRperiod); QDateTime t1=QDateTime::currentDateTimeUtc().addSecs(-n); - if(m_TRperiod < 60) { + if(m_TRperiod<60.0) { t=t1.toString("hh:mm:ss") + " " + m_rxBand; } else { t=t1.toString("hh:mm") + " " + m_rxBand; @@ -409,7 +411,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() } float bw=9.0*12000.0/m_nsps; //JT9 - + if(m_mode=="FT4") bw=3*12000.0/576.0; //FT4 ### (3x, or 4x???) ### if(m_mode=="FT8") bw=7*12000.0/1920.0; //FT8 if(m_mode=="JT4") { //JT4 @@ -484,7 +486,8 @@ void CPlotter::DrawOverlay() //DrawOverlay() painter0.drawLine(x1,24,x1,30); } - if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or m_mode=="QRA64" or m_mode=="FT8") { + if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" + or m_mode=="QRA64" or m_mode=="FT8" or m_mode=="FT4") { if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) { painter0.setPen(penGreen); @@ -518,7 +521,8 @@ void CPlotter::DrawOverlay() //DrawOverlay() } if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or - m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="FT8") { + m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="FT8" + or m_mode=="FT4") { painter0.setPen(penRed); x1=XfromFreq(m_txFreq); x2=XfromFreq(m_txFreq+bw); @@ -717,9 +721,9 @@ void CPlotter::mouseDoubleClickEvent (QMouseEvent * event) } } -void CPlotter::setNsps(int ntrperiod, int nsps) //setNsps +void CPlotter::setNsps(double trperiod, int nsps) //setNsps { - m_TRperiod=ntrperiod; + m_TRperiod=trperiod; m_nsps=nsps; m_fftBinWidth=1500.0/2048.0; if(m_nsps==15360) m_fftBinWidth=1500.0/2048.0; diff --git a/widgets/plotter.h b/widgets/plotter.h index e243c1777..2cbfd202b 100644 --- a/widgets/plotter.h +++ b/widgets/plotter.h @@ -56,7 +56,7 @@ public: void DrawOverlay(); int rxFreq(); void setFsample(int n); - void setNsps(int ntrperiod, int nsps); + void setNsps(double trperiod, int nsps); void setTxFreq(int n); void setMode(QString mode); void setSubMode(int n); @@ -145,6 +145,7 @@ private: double m_fftBinWidth; double m_dialFreq; double m_xOffset; + double m_TRperiod; float m_sum[2048]; @@ -161,7 +162,6 @@ private: qint32 m_h; qint32 m_h1; qint32 m_h2; - qint32 m_TRperiod; qint32 m_rxFreq; qint32 m_txFreq; qint32 m_fMin; diff --git a/widgets/widegraph.cpp b/widgets/widegraph.cpp index b4601ba4c..6234f731a 100644 --- a/widgets/widegraph.cpp +++ b/widgets/widegraph.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "ui_widegraph.h" #include "commons.h" #include "Configuration.hpp" @@ -23,7 +24,7 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) : ui(new Ui::WideGraph), m_settings (settings), m_palettes_path {":/Palettes"}, - m_ntr0 {0}, + m_tr0 {0.0}, m_n {0}, m_bHaveTransmitted {false} { @@ -186,8 +187,8 @@ void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dat // Time according to this computer qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - int ntr = (ms/1000) % m_TRperiod; - if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && ntrwidePlot->draw(swide,true,false); } } @@ -277,11 +278,11 @@ int WideGraph::fSpan() return ui->widePlot->fSpan (); } -void WideGraph::setPeriod(int ntrperiod, int nsps) //SetPeriod +void WideGraph::setPeriod(double trperiod, int nsps) //SetPeriod { - m_TRperiod=ntrperiod; + m_TRperiod=trperiod; m_nsps=nsps; - ui->widePlot->setNsps(ntrperiod, nsps); + ui->widePlot->setNsps(trperiod, nsps); } void WideGraph::setTxFreq(int n) //setTxFreq diff --git a/widgets/widegraph.h b/widgets/widegraph.h index a809a6c8c..c87bab050 100644 --- a/widgets/widegraph.h +++ b/widgets/widegraph.h @@ -35,7 +35,7 @@ public: int fSpan(); void saveSettings(); void setFsample(int n); - void setPeriod(int ntrperiod, int nsps); + void setPeriod(double trperiod, int nsps); void setTxFreq(int n); void setMode(QString mode); void setSubMode(int n); @@ -95,10 +95,11 @@ private: WFPalette m_userPalette; QHash m_fMinPerBand; + double m_tr0; + double m_TRperiod; + qint32 m_waterfallAvg; - qint32 m_TRperiod; qint32 m_nsps; - qint32 m_ntr0; qint32 m_fMax; qint32 m_nSubMode; qint32 m_nsmo; @@ -108,7 +109,7 @@ private: bool m_bFlatten; bool m_bRef; - bool m_bHaveTransmitted; //Set true at end of a WSPR transmission + bool m_bHaveTransmitted; //Set true at end of a WSPR or FT4 transmission QString m_rxBand; QString m_mode; diff --git a/widgets/widgets.pri b/widgets/widgets.pri index 24ddd5a3c..3c2cb2444 100644 --- a/widgets/widgets.pri +++ b/widgets/widgets.pri @@ -8,18 +8,20 @@ SOURCES += \ widgets/fastplot.cpp widgets/MessageBox.cpp \ widgets/colorhighlighting.cpp widgets/ExportCabrillo.cpp \ widgets/AbstractLogWindow.cpp \ + widgets/FrequencyLineEdit.cpp widgets/FrequencyDeltaLineEdit.cpp \ widgets/FoxLogWindow.cpp widgets/CabrilloLogWindow.cpp HEADERS += \ widgets/mainwindow.h widgets/plotter.h \ widgets/about.h widgets/widegraph.h \ widgets/displaytext.h widgets/logqso.h widgets/LettersSpinBox.hpp \ - widgets/FrequencyLineEdit.hpp widgets/signalmeter.h \ + widgets/FrequencyLineEdit.hpp widgets/FrequencyDeltaLineEdit.hpp widgets/signalmeter.h \ widgets/meterwidget.h widgets/messageaveraging.h \ widgets/echoplot.h widgets/echograph.h widgets/fastgraph.h \ widgets/fastplot.h widgets/MessageBox.hpp widgets/colorhighlighting.h \ widgets/ExportCabrillo.h widgets/AbstractLogWindow.hpp \ - widgets/FoxLogWindow.hpp widgets/CabrilloLogWindow.hpp + widgets/FoxLogWindow.hpp widgets/CabrilloLogWindow.hpp \ + widgets/DateTimeEdit.hpp FORMS += \ widgets/mainwindow.ui widgets/about.ui \