mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-10-31 15:47:10 -04:00
Rig control overhaul to implement generic Doppler shift tracking
The concept of a nominal receive and transmit frequency has been introduced. This is used as a base frequency for Doppler correction, frequency setting and reporting. The start up frequency is now zero which is updated by the first rig control status report. This needs more work to accommodate calling frequency plus working frequency operation as is used for random MS operation etc.. The main window frequency display now shows the transmit dial frequency while transmitting. The mode changing logic sequence has been changed such that the rig is correctly put into and taken out of split mode as required by the target mode. This also avoids the "other" VFO having its frequency changed when entering a mode that does not use split operating like WSPR. The main window band combo box edit may now be used to input an kHz offset from the current MHz dial frequency. This is intended for setting a sked or working frequency on the VHF and up bands. For example the working frequency for 23cms might be set to 1296MHz and a working frequency of 1296.3MHz would be selected by selecting the 23cms band with the combo box drop down list and then entering 300k into the band combo box edit widget. When using JT4 modes a CTRL+Click on the waterfall adjusts the nominal frequency such that the frequency clicked on becomes the Tx and Rx frequency using the fixed 1000Hz DF that JT4 modes use. This will probably be extended to all QSO modes when used in VHF & up mode. This assumes that 1000Hz is an optimal DF for both Tx and Rx and therefore one can "net" to an off frequency, but visible on the waterfall, caller with one click. Improvements to OmniRig rig control including use of the serial port control lines RTS or DTR, on the CAT serial port used by OmniRig, for PTT control. Incrementing transaction sequence numbers added to messages to and from the rig control thread. This enables round trip status to be tracked and associated with a request. For example a command that might cause several asynchronous status updates can now be tracked in the originating thread such that it is clear which updates are caused by executing the request. This in turn allows updates to be held until the request is complete i.e. the state is consistent with the results of the request. Messages to the rig control thread are now posted as a new state (Transceiver::TransceiverState) object. The rig control thread tracks requests and actions any differences between the prior requests and the new state. The rig control thread is now stored on the heap so that it can be closed down and released as needed. Along with this the rig control close down semantics are better defined avoiding some potential deadlock situations. If the rig is placed into split mode it will be reverted to simplex mode when the rig connection is closed. When using direct rig control via Hamlib, rigs that have A/B VFO arrangements and no method to query the current VFO like many Icoms and the Yaesu FT-817/857/897(D) series now have smarted frequency updating requiring no VFO changes when changing the frequency. This is particularly important when doing Tx Doppler correction to avoid glitches. The implementation of emulated split operating mode ("Fake It") is simplified and improved. A dummy Hamlib transceiver for PTT control on a separate port is no long instantiated if CAT or VOX PTT control is selected. The resolution and any rounding of the rig CAT frequency set and get commands is determined automatically upon opening the rig connection. This is needed to determine the rate of frequency updates for Doppler tracking. It also allows the rig to be more accurately controlled. Frequency calibration is calculated separately for the receive and transmit frequencies. Whether the rig modulation mode should be controlled is now a constructor argument rather than being passed with individual rig control requests. Doppler shift correction is considerably enhanced with simpler controls and much better rig control. A new mode of tracking called "receive only" is introduced for those with rigs that cannot be QSY:ed via CAT when transmitting. Such rigs have a Doppler correction calculated for the middle of the next transmit period just before transmission starts. While using Doppler tracking it is now possible to adjust the sked frequency either using the new kHz offset feature of the main window band combo box or by directly tuning the rig VFO knob while holding down the CTRL key. The astronomical data window that includes Doppler tracking control is now opened and closed using a checkable menu item to avoid it being accidentally closed. Debug configuration rig control diagnostic messages now have a facility argument for clearer and more standardized trace messages. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6590 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
4a73a69ca9
commit
468f384346
@ -372,7 +372,7 @@ private:
|
||||
void set_application_font (QFont const&);
|
||||
|
||||
void initialize_models ();
|
||||
bool open_rig ();
|
||||
bool open_rig (bool force = false);
|
||||
//bool set_mode ();
|
||||
void close_rig ();
|
||||
TransceiverFactory::ParameterPack gather_rig_data ();
|
||||
@ -416,8 +416,8 @@ private:
|
||||
Q_SLOT void insert_frequency ();
|
||||
Q_SLOT void delete_stations ();
|
||||
Q_SLOT void insert_station ();
|
||||
Q_SLOT void handle_transceiver_update (TransceiverState);
|
||||
Q_SLOT void handle_transceiver_failure (QString reason);
|
||||
Q_SLOT void handle_transceiver_update (TransceiverState const&, unsigned sequence_number);
|
||||
Q_SLOT void handle_transceiver_failure (QString const& reason);
|
||||
Q_SLOT void on_pbCQmsg_clicked();
|
||||
Q_SLOT void on_pbMyCall_clicked();
|
||||
Q_SLOT void on_pbTxMsg_clicked();
|
||||
@ -425,17 +425,14 @@ private:
|
||||
Q_SLOT void on_pbNewCall_clicked();
|
||||
|
||||
// typenames used as arguments must match registered type names :(
|
||||
Q_SIGNAL void start_transceiver () const;
|
||||
Q_SIGNAL void stop_transceiver (bool reset_split) const;
|
||||
Q_SIGNAL void frequency (Frequency rx, Transceiver::MODE) const;
|
||||
Q_SIGNAL void tx_frequency (Frequency tx, bool rationalize_mode) const;
|
||||
Q_SIGNAL void mode (Transceiver::MODE, bool rationalize) const;
|
||||
Q_SIGNAL void ptt (bool) const;
|
||||
Q_SIGNAL void sync (bool force_signal) const;
|
||||
Q_SIGNAL void start_transceiver (unsigned seqeunce_number) const;
|
||||
Q_SIGNAL void set_transceiver (Transceiver::TransceiverState const&,
|
||||
unsigned sequence_number) const;
|
||||
Q_SIGNAL void stop_transceiver () const;
|
||||
|
||||
Configuration * const self_; // back pointer to public interface
|
||||
|
||||
QThread transceiver_thread_;
|
||||
QThread * transceiver_thread_;
|
||||
TransceiverFactory transceiver_factory_;
|
||||
QList<QMetaObject::Connection> rig_connections_;
|
||||
|
||||
@ -473,6 +470,7 @@ private:
|
||||
StationList stations_;
|
||||
StationList next_stations_;
|
||||
FrequencyDelta current_offset_;
|
||||
FrequencyDelta current_tx_offset_;
|
||||
|
||||
QAction * frequency_delete_action_;
|
||||
QAction * frequency_insert_action_;
|
||||
@ -489,24 +487,10 @@ private:
|
||||
bool have_rig_;
|
||||
bool rig_changed_;
|
||||
TransceiverState cached_rig_state_;
|
||||
int rig_resolution_; // see Transceiver::resolution signal
|
||||
double frequency_calibration_intercept_;
|
||||
double frequency_calibration_slope_ppm_;
|
||||
|
||||
// the following members are required to get the rig into split the
|
||||
// first time monitor or tune or Tx occur
|
||||
bool setup_split_;
|
||||
Frequency required_tx_frequency_; // this is needed because DX Lab
|
||||
// Suite Commander in particular
|
||||
// insists on reporting out of
|
||||
// date state after successful
|
||||
// commands to change the rig
|
||||
// state :( Zero is valid and it
|
||||
// means that we don't know the Tx
|
||||
// frequency rather than implying
|
||||
// no split.
|
||||
|
||||
bool enforce_mode_and_split_;
|
||||
bool reset_split_;
|
||||
unsigned transceiver_command_number_;
|
||||
|
||||
// configuration fields that we publish
|
||||
QString my_callsign_;
|
||||
@ -588,6 +572,7 @@ QDir Configuration::data_dir () const {return m_->data_dir_;}
|
||||
QDir Configuration::temp_dir () const {return m_->temp_dir_;}
|
||||
|
||||
int Configuration::exec () {return m_->exec ();}
|
||||
bool Configuration::is_active () const {return m_->isVisible ();}
|
||||
|
||||
QAudioDeviceInfo const& Configuration::audio_input_device () const {return m_->audio_input_device_;}
|
||||
AudioDevice::Channel Configuration::audio_input_channel () const {return m_->audio_input_channel_;}
|
||||
@ -668,13 +653,18 @@ bool Configuration::transceiver_online (bool open_if_closed)
|
||||
return m_->have_rig (open_if_closed);
|
||||
}
|
||||
|
||||
int Configuration::transceiver_resolution () const
|
||||
{
|
||||
return m_->rig_resolution_;
|
||||
}
|
||||
|
||||
void Configuration::transceiver_offline ()
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::transceiver_offline:" << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
return m_->close_rig ();
|
||||
m_->close_rig ();
|
||||
}
|
||||
|
||||
void Configuration::transceiver_frequency (Frequency f)
|
||||
@ -691,8 +681,6 @@ void Configuration::transceiver_tx_frequency (Frequency f)
|
||||
qDebug () << "Configuration::transceiver_tx_frequency:" << f << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
m_->setup_split_ = true;
|
||||
m_->required_tx_frequency_ = f;
|
||||
m_->transceiver_tx_frequency (f);
|
||||
}
|
||||
|
||||
@ -720,10 +708,11 @@ void Configuration::sync_transceiver (bool force_signal, bool enforce_mode_and_s
|
||||
qDebug () << "Configuration::sync_transceiver: force signal:" << force_signal << "enforce_mode_and_split:" << enforce_mode_and_split << m_->cached_rig_state_;
|
||||
#endif
|
||||
|
||||
m_->enforce_mode_and_split_ = enforce_mode_and_split;
|
||||
m_->setup_split_ = enforce_mode_and_split;
|
||||
m_->required_tx_frequency_ = 0;
|
||||
m_->sync_transceiver (force_signal);
|
||||
if (!enforce_mode_and_split)
|
||||
{
|
||||
m_->transceiver_tx_frequency (0);
|
||||
}
|
||||
}
|
||||
|
||||
Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget * parent)
|
||||
@ -738,15 +727,14 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget *
|
||||
, stations_ {&bands_}
|
||||
, next_stations_ {&bands_}
|
||||
, current_offset_ {0}
|
||||
, current_tx_offset_ {0}
|
||||
, frequency_dialog_ {new FrequencyDialog {&modes_, this}}
|
||||
, station_dialog_ {new StationDialog {&next_stations_, &bands_, this}}
|
||||
, rig_active_ {false}
|
||||
, have_rig_ {false}
|
||||
, rig_changed_ {false}
|
||||
// , ptt_state_ {false}
|
||||
, setup_split_ {false}
|
||||
, required_tx_frequency_ {0}
|
||||
, enforce_mode_and_split_ {false}
|
||||
, rig_resolution_ {0}
|
||||
, transceiver_command_number_ {0}
|
||||
, degrade_ {0.} // initialize to zero each run, not
|
||||
// saved in settings
|
||||
, default_audio_input_device_selected_ {false}
|
||||
@ -1018,18 +1006,15 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget *
|
||||
enumerate_rigs ();
|
||||
initialize_models ();
|
||||
|
||||
transceiver_thread_.start ();
|
||||
transceiver_thread_ = new QThread {this};
|
||||
transceiver_thread_->start ();
|
||||
}
|
||||
|
||||
Configuration::impl::~impl ()
|
||||
{
|
||||
transceiver_thread_->quit ();
|
||||
transceiver_thread_->wait ();
|
||||
write_settings ();
|
||||
|
||||
close_rig ();
|
||||
|
||||
transceiver_thread_.quit ();
|
||||
transceiver_thread_.wait ();
|
||||
|
||||
temp_dir_.removeRecursively (); // clean up temp files
|
||||
}
|
||||
|
||||
@ -1092,7 +1077,6 @@ void Configuration::impl::initialize_models ()
|
||||
ui_->rig_combo_box->setCurrentText (rig_params_.rig_name);
|
||||
ui_->TX_mode_button_group->button (data_mode_)->setChecked (true);
|
||||
ui_->split_mode_button_group->button (rig_params_.split_mode)->setChecked (true);
|
||||
ui_->reset_split_check_box->setChecked (reset_split_);
|
||||
ui_->CAT_serial_baud_combo_box->setCurrentText (QString::number (rig_params_.baud));
|
||||
ui_->CAT_data_bits_button_group->button (rig_params_.data_bits)->setChecked (true);
|
||||
ui_->CAT_stop_bits_button_group->button (rig_params_.stop_bits)->setChecked (true);
|
||||
@ -1318,8 +1302,8 @@ void Configuration::impl::read_settings ()
|
||||
EMEonly_ = settings_->value("EMEonly",false).toBool ();
|
||||
offsetRxFreq_ = settings_->value("OffsetRx",false).toBool();
|
||||
rig_params_.poll_interval = settings_->value ("Polling", 0).toInt ();
|
||||
rig_params_.set_rig_mode = data_mode_ != data_mode_none;
|
||||
rig_params_.split_mode = settings_->value ("SplitMode", QVariant::fromValue (TransceiverFactory::split_mode_none)).value<TransceiverFactory::SplitMode> ();
|
||||
reset_split_ = settings_->value ("ResetSplitOnExit", true).toBool ();
|
||||
udp_server_name_ = settings_->value ("UDPServer", "127.0.0.1").toString ();
|
||||
udp_server_port_ = settings_->value ("UDPServerPort", 2237).toUInt ();
|
||||
accept_udp_requests_ = settings_->value ("AcceptUDPRequests", false).toBool ();
|
||||
@ -1407,7 +1391,6 @@ void Configuration::impl::write_settings ()
|
||||
settings_->setValue ("TXAudioSource", QVariant::fromValue (rig_params_.audio_source));
|
||||
settings_->setValue ("Polling", rig_params_.poll_interval);
|
||||
settings_->setValue ("SplitMode", QVariant::fromValue (rig_params_.split_mode));
|
||||
settings_->setValue ("ResetSplitOnExit", reset_split_);
|
||||
settings_->setValue ("VHFUHF", enable_VHF_features_);
|
||||
settings_->setValue ("Decode52", decode_at_52s_);
|
||||
settings_->setValue ("SingleDecode", single_decode_);
|
||||
@ -1644,6 +1627,7 @@ TransceiverFactory::ParameterPack Configuration::impl::gather_rig_data ()
|
||||
result.ptt_type = static_cast<TransceiverFactory::PTTMethod> (ui_->PTT_method_button_group->checkedId ());
|
||||
result.ptt_port = ui_->PTT_port_combo_box->currentText ();
|
||||
result.audio_source = static_cast<TransceiverFactory::TXAudioSource> (ui_->TX_audio_source_button_group->checkedId ());
|
||||
result.set_rig_mode = static_cast<DataMode> (ui_->TX_mode_button_group->checkedId ()) != data_mode_none;
|
||||
result.split_mode = static_cast<TransceiverFactory::SplitMode> (ui_->split_mode_button_group->checkedId ());
|
||||
return result;
|
||||
}
|
||||
@ -1815,7 +1799,6 @@ void Configuration::impl::accept ()
|
||||
NDxG_ = ui_->cbNDxG->isChecked ();
|
||||
NN_ = ui_->cbNN->isChecked ();
|
||||
EMEonly_ = ui_->cbEMEonly->isChecked ();
|
||||
reset_split_ = ui_->reset_split_check_box->isChecked ();
|
||||
|
||||
offsetRxFreq_ = ui_->offset_Rx_freq_check_box->isChecked();
|
||||
frequency_calibration_intercept_ = ui_->calibration_intercept_spin_box->value ();
|
||||
@ -2003,8 +1986,6 @@ void Configuration::impl::on_CAT_poll_interval_spin_box_valueChanged (int /* val
|
||||
|
||||
void Configuration::impl::on_split_mode_button_group_buttonClicked (int /* id */)
|
||||
{
|
||||
setup_split_ = true;
|
||||
required_tx_frequency_ = 0;
|
||||
set_rig_invariants ();
|
||||
}
|
||||
|
||||
@ -2016,9 +1997,9 @@ void Configuration::impl::on_test_CAT_push_button_clicked ()
|
||||
}
|
||||
|
||||
ui_->test_CAT_push_button->setStyleSheet ({});
|
||||
if (open_rig ())
|
||||
if (open_rig (true))
|
||||
{
|
||||
Q_EMIT sync (true);
|
||||
//Q_EMIT sync (true);
|
||||
}
|
||||
|
||||
set_rig_invariants ();
|
||||
@ -2218,52 +2199,58 @@ bool Configuration::impl::have_rig (bool open_if_closed)
|
||||
return rig_active_;
|
||||
}
|
||||
|
||||
bool Configuration::impl::open_rig ()
|
||||
bool Configuration::impl::open_rig (bool force)
|
||||
{
|
||||
auto result = false;
|
||||
|
||||
auto const rig_data = gather_rig_data ();
|
||||
if (!rig_active_ || rig_data != saved_rig_params_)
|
||||
if (force || !rig_active_ || rig_data != saved_rig_params_)
|
||||
{
|
||||
try
|
||||
{
|
||||
close_rig ();
|
||||
|
||||
// create a new Transceiver object
|
||||
auto rig = transceiver_factory_.create (rig_data, &transceiver_thread_);
|
||||
auto rig = transceiver_factory_.create (rig_data, transceiver_thread_);
|
||||
cached_rig_state_ = Transceiver::TransceiverState {};
|
||||
|
||||
// hook up Configuration transceiver control signals to Transceiver slots
|
||||
//
|
||||
// these connections cross the thread boundary
|
||||
rig_connections_ << connect (this, &Configuration::impl::frequency, rig.get (), &Transceiver::frequency);
|
||||
rig_connections_ << connect (this, &Configuration::impl::tx_frequency, rig.get (), &Transceiver::tx_frequency);
|
||||
rig_connections_ << connect (this, &Configuration::impl::mode, rig.get (), &Transceiver::mode);
|
||||
rig_connections_ << connect (this, &Configuration::impl::ptt, rig.get (), &Transceiver::ptt);
|
||||
rig_connections_ << connect (this, &Configuration::impl::sync, rig.get (), &Transceiver::sync);
|
||||
rig_connections_ << connect (this, &Configuration::impl::set_transceiver,
|
||||
rig.get (), &Transceiver::set);
|
||||
|
||||
// hook up Transceiver signals to Configuration signals
|
||||
//
|
||||
// these connections cross the thread boundary
|
||||
connect (rig.get (), &Transceiver::update, this, &Configuration::impl::handle_transceiver_update);
|
||||
connect (rig.get (), &Transceiver::failure, this, &Configuration::impl::handle_transceiver_failure);
|
||||
rig_connections_ << connect (rig.get (), &Transceiver::resolution, this, [=] (int resolution) {
|
||||
rig_resolution_ = resolution;
|
||||
});
|
||||
rig_connections_ << connect (rig.get (), &Transceiver::update, this, &Configuration::impl::handle_transceiver_update);
|
||||
rig_connections_ << connect (rig.get (), &Transceiver::failure, this, &Configuration::impl::handle_transceiver_failure);
|
||||
|
||||
// setup thread safe startup and close down semantics
|
||||
rig_connections_ << connect (this, &Configuration::impl::start_transceiver, rig.get (), &Transceiver::start);
|
||||
connect (this, &Configuration::impl::stop_transceiver, rig.get (), &Transceiver::stop);
|
||||
rig_connections_ << connect (this, &Configuration::impl::stop_transceiver, rig.get (), &Transceiver::stop);
|
||||
|
||||
auto p = rig.release (); // take ownership
|
||||
// schedule eventual destruction
|
||||
|
||||
// schedule destruction on thread quit
|
||||
connect (transceiver_thread_, &QThread::finished, p, &QObject::deleteLater);
|
||||
|
||||
// schedule eventual destruction for non-closing situations
|
||||
//
|
||||
// must be queued connection to avoid premature self-immolation
|
||||
// since finished signal is going to be emitted from the object
|
||||
// that will get destroyed in its own stop slot i.e. a same
|
||||
// thread signal to slot connection which by default will be
|
||||
// reduced to a method function call.
|
||||
// must be queued connection to avoid premature
|
||||
// self-immolation since finished signal is going to be
|
||||
// emitted from the object that will get destroyed in its
|
||||
// own stop slot i.e. a same thread signal to slot
|
||||
// connection which by default will be reduced to a method
|
||||
// function call.
|
||||
connect (p, &Transceiver::finished, p, &Transceiver::deleteLater, Qt::QueuedConnection);
|
||||
|
||||
ui_->test_CAT_push_button->setStyleSheet ({});
|
||||
rig_active_ = true;
|
||||
Q_EMIT start_transceiver (); // start rig on its thread
|
||||
Q_EMIT start_transceiver (++transceiver_command_number_); // start rig on its thread
|
||||
result = true;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
@ -2284,98 +2271,85 @@ bool Configuration::impl::open_rig ()
|
||||
void Configuration::impl::transceiver_frequency (Frequency f)
|
||||
{
|
||||
Transceiver::MODE mode {Transceiver::UNK};
|
||||
if (ui_->mode_group_box->isEnabled ())
|
||||
switch (data_mode_)
|
||||
{
|
||||
switch (static_cast<DataMode> (ui_->TX_mode_button_group->checkedId ()))
|
||||
{
|
||||
case data_mode_USB: mode = Transceiver::USB; break;
|
||||
case data_mode_data: mode = Transceiver::DIG_U; break;
|
||||
case data_mode_none: break;
|
||||
}
|
||||
case data_mode_USB: mode = Transceiver::USB; break;
|
||||
case data_mode_data: mode = Transceiver::DIG_U; break;
|
||||
case data_mode_none: break;
|
||||
}
|
||||
|
||||
if (cached_rig_state_.frequency () != f
|
||||
|| (mode != Transceiver::UNK && mode != cached_rig_state_.mode ()))
|
||||
{
|
||||
cached_rig_state_.frequency (f);
|
||||
cached_rig_state_.mode (mode);
|
||||
cached_rig_state_.online (true); // we want the rig online
|
||||
cached_rig_state_.mode (mode);
|
||||
|
||||
// apply any offset & calibration
|
||||
// we store the offset here for use in feedback from the rig, we
|
||||
// cannot absolutely determine if the offset should apply but by
|
||||
// simply picking an offset when the Rx frequency is set and
|
||||
// sticking to it we get sane behaviour
|
||||
current_offset_ = stations_.offset (f);
|
||||
Q_EMIT frequency (apply_calibration (f + current_offset_), mode);
|
||||
}
|
||||
// apply any offset & calibration
|
||||
// we store the offset here for use in feedback from the rig, we
|
||||
// cannot absolutely determine if the offset should apply but by
|
||||
// simply picking an offset when the Rx frequency is set and
|
||||
// sticking to it we get sane behaviour
|
||||
current_offset_ = stations_.offset (f);
|
||||
cached_rig_state_.frequency (apply_calibration (f + current_offset_));
|
||||
|
||||
Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_);
|
||||
}
|
||||
|
||||
void Configuration::impl::transceiver_tx_frequency (Frequency f)
|
||||
{
|
||||
if (/* set_mode () || */ cached_rig_state_.tx_frequency () != f || !cached_rig_state_.compare_split (!!f))
|
||||
cached_rig_state_.online (true); // we want the rig online
|
||||
cached_rig_state_.split (f);
|
||||
cached_rig_state_.tx_frequency (f);
|
||||
|
||||
// lookup offset for tx and apply calibration
|
||||
if (f)
|
||||
{
|
||||
cached_rig_state_.split (f);
|
||||
cached_rig_state_.tx_frequency (f);
|
||||
|
||||
// lookup offset and apply calibration if we are in split mode
|
||||
if (cached_rig_state_.split ())
|
||||
{
|
||||
// apply and offset and calibration
|
||||
// we store the offset here for use in feedback from the
|
||||
// rig, we cannot absolutely determine if the offset should
|
||||
// apply but by simply picking an offset when the Rx
|
||||
// frequency is set and sticking to it we get sane behaviour
|
||||
current_offset_ = stations_.offset (f);
|
||||
f = apply_calibration (f + current_offset_);
|
||||
}
|
||||
|
||||
|
||||
// Rationalise TX VFO mode if we ask for split and are
|
||||
// responsible for mode.
|
||||
Q_EMIT tx_frequency (f, cached_rig_state_.split ()
|
||||
&& ui_->mode_group_box->isEnabled ()
|
||||
&& data_mode_none != data_mode_);
|
||||
// apply and offset and calibration
|
||||
// we store the offset here for use in feedback from the
|
||||
// rig, we cannot absolutely determine if the offset should
|
||||
// apply but by simply picking an offset when the Rx
|
||||
// frequency is set and sticking to it we get sane behaviour
|
||||
current_tx_offset_ = stations_.offset (f);
|
||||
cached_rig_state_.tx_frequency (apply_calibration (f + current_tx_offset_));
|
||||
}
|
||||
|
||||
Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_);
|
||||
}
|
||||
|
||||
void Configuration::impl::transceiver_mode (MODE m)
|
||||
{
|
||||
if (cached_rig_state_.mode () != m)
|
||||
{
|
||||
cached_rig_state_.mode (m);
|
||||
|
||||
// Rationalise mode if we are responsible for it and in split mode.
|
||||
Q_EMIT mode (m, cached_rig_state_.split ()
|
||||
&& ui_->mode_group_box->isEnabled ()
|
||||
&& data_mode_none != data_mode_);
|
||||
}
|
||||
cached_rig_state_.online (true); // we want the rig online
|
||||
cached_rig_state_.mode (m);
|
||||
Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_);
|
||||
}
|
||||
|
||||
void Configuration::impl::transceiver_ptt (bool on)
|
||||
{
|
||||
cached_rig_state_.online (true); // we want the rig online
|
||||
cached_rig_state_.ptt (on);
|
||||
|
||||
// pass this on regardless of cache
|
||||
Q_EMIT ptt (on);
|
||||
Q_EMIT set_transceiver (cached_rig_state_, ++transceiver_command_number_);
|
||||
}
|
||||
|
||||
void Configuration::impl::sync_transceiver (bool force_signal)
|
||||
void Configuration::impl::sync_transceiver (bool /*force_signal*/)
|
||||
{
|
||||
// pass this on as cache must be ignored
|
||||
Q_EMIT sync (force_signal);
|
||||
// Q_EMIT sync (force_signal);
|
||||
}
|
||||
|
||||
void Configuration::impl::handle_transceiver_update (TransceiverState state)
|
||||
void Configuration::impl::handle_transceiver_update (TransceiverState const& state,
|
||||
unsigned sequence_number)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::handle_transceiver_update: Transceiver State:" << state;
|
||||
qDebug () << "Configuration::handle_transceiver_update: Transceiver State #:" << sequence_number << state;
|
||||
#endif
|
||||
|
||||
// only follow rig on some information, ignore other stuff
|
||||
cached_rig_state_.online (state.online ());
|
||||
cached_rig_state_.frequency (state.frequency ());
|
||||
cached_rig_state_.mode (state.mode ());
|
||||
cached_rig_state_.split (state.split ());
|
||||
|
||||
if (state.online ())
|
||||
{
|
||||
ui_->test_PTT_push_button->setChecked (state.ptt ());
|
||||
|
||||
TransceiverFactory::SplitMode split_mode_selected;
|
||||
if (isVisible ())
|
||||
{
|
||||
ui_->test_CAT_push_button->setStyleSheet ("QPushButton {background-color: green;}");
|
||||
@ -2386,80 +2360,37 @@ void Configuration::impl::handle_transceiver_update (TransceiverState state)
|
||||
ui_->test_PTT_push_button->setEnabled ((TransceiverFactory::PTT_method_CAT == ptt_method && CAT_PTT_enabled)
|
||||
|| TransceiverFactory::PTT_method_DTR == ptt_method
|
||||
|| TransceiverFactory::PTT_method_RTS == ptt_method);
|
||||
|
||||
|
||||
// Follow the setup choice.
|
||||
split_mode_selected = static_cast<TransceiverFactory::SplitMode> (ui_->split_mode_button_group->checkedId ());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Follow the rig unless configuration has been changed.
|
||||
split_mode_selected = static_cast<TransceiverFactory::SplitMode> (rig_params_.split_mode);
|
||||
|
||||
if (enforce_mode_and_split_)
|
||||
{
|
||||
if (TransceiverFactory::basic_transceiver_name_ != ui_->rig_combo_box->currentText ()
|
||||
&& ((TransceiverFactory::split_mode_none != split_mode_selected) != state.split ()))
|
||||
{
|
||||
if (!setup_split_)
|
||||
{
|
||||
// Rig split mode isn't consistent with settings so
|
||||
// change settings.
|
||||
//
|
||||
// For rigs that can't report split mode changes
|
||||
// (e.g.Icom) this is going to confuse operators, but
|
||||
// what can we do if they change the rig?
|
||||
// auto split_mode = state.split () ? TransceiverFactory::split_mode_rig : TransceiverFactory::split_mode_none;
|
||||
// rig_params_.split_mode = split_mode;
|
||||
// ui_->split_mode_button_group->button (split_mode)->setChecked (true);
|
||||
// split_mode_selected = split_mode;
|
||||
setup_split_ = true;
|
||||
required_tx_frequency_ = 0;
|
||||
|
||||
// Q_EMIT self_->transceiver_failure (tr ("Rig
|
||||
// split mode setting not consistent with WSJT-X
|
||||
// settings. Changing WSJT-X settings for
|
||||
// you."));
|
||||
if (cached_rig_state_.split () != state.split ())
|
||||
{
|
||||
Q_EMIT self_->transceiver_failure (tr ("Rig split mode setting not consistent with WSJT-X settings."));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// One time rig setup split
|
||||
if (setup_split_ && cached_rig_state_.split () != state.split ())
|
||||
{
|
||||
Q_EMIT tx_frequency (TransceiverFactory::split_mode_none != split_mode_selected && cached_rig_state_.split ()
|
||||
? (required_tx_frequency_ ? required_tx_frequency_ : state.tx_frequency ())
|
||||
: 0, true);
|
||||
}
|
||||
setup_split_ = false;
|
||||
required_tx_frequency_ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
close_rig ();
|
||||
}
|
||||
|
||||
// take off calibration & offset
|
||||
state.frequency (remove_calibration (state.frequency ()) - current_offset_);
|
||||
|
||||
if (state.tx_frequency ())
|
||||
// pass on to clients if current command is processed
|
||||
if (sequence_number == transceiver_command_number_)
|
||||
{
|
||||
TransceiverState reported_state {state};
|
||||
// take off calibration & offset
|
||||
state.tx_frequency (remove_calibration (state.tx_frequency ()) - current_offset_);
|
||||
reported_state.frequency (remove_calibration (reported_state.frequency ()) - current_offset_);
|
||||
|
||||
if (reported_state.tx_frequency ())
|
||||
{
|
||||
// take off calibration & offset
|
||||
reported_state.tx_frequency (remove_calibration (reported_state.tx_frequency ()) - current_tx_offset_);
|
||||
}
|
||||
|
||||
Q_EMIT self_->transceiver_update (reported_state);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::handle_transceiver_update: skipping because of command #:" << transceiver_command_number_;
|
||||
#endif
|
||||
}
|
||||
|
||||
cached_rig_state_ = state;
|
||||
|
||||
// pass on to clients
|
||||
Q_EMIT self_->transceiver_update (cached_rig_state_);
|
||||
}
|
||||
|
||||
void Configuration::impl::handle_transceiver_failure (QString reason)
|
||||
void Configuration::impl::handle_transceiver_failure (QString const& reason)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "Configuration::handle_transceiver_failure: reason:" << reason;
|
||||
@ -2487,7 +2418,7 @@ void Configuration::impl::close_rig ()
|
||||
if (rig_active_)
|
||||
{
|
||||
ui_->test_CAT_push_button->setStyleSheet ("QPushButton {background-color: red;}");
|
||||
Q_EMIT stop_transceiver (reset_split_);
|
||||
Q_EMIT stop_transceiver ();
|
||||
Q_FOREACH (auto const& connection, rig_connections_)
|
||||
{
|
||||
disconnect (connection);
|
||||
|
@ -72,6 +72,7 @@ public:
|
||||
~Configuration ();
|
||||
|
||||
int exec ();
|
||||
bool is_active () const;
|
||||
|
||||
QDir temp_dir () const;
|
||||
QDir doc_dir () const;
|
||||
@ -155,6 +156,15 @@ public:
|
||||
// open_if_closed parameter is passed as true.
|
||||
bool transceiver_online (bool open_if_closed = false);
|
||||
|
||||
// Frequency resolution of the rig
|
||||
//
|
||||
// 0 - 1Hz
|
||||
// 1 - 10Hz rounded
|
||||
// -1 - 10Hz truncated
|
||||
// 2 - 100Hz rounded
|
||||
// -2 - 100Hz truncated
|
||||
int transceiver_resolution () const;
|
||||
|
||||
// Close down connection to rig.
|
||||
void transceiver_offline ();
|
||||
|
||||
@ -206,7 +216,7 @@ public:
|
||||
//
|
||||
|
||||
// signals a change in one of the TransceiverState members
|
||||
Q_SIGNAL void transceiver_update (Transceiver::TransceiverState) const;
|
||||
Q_SIGNAL void transceiver_update (Transceiver::TransceiverState const&) const;
|
||||
|
||||
// Signals a failure of a control rig CAT or PTT connection.
|
||||
//
|
||||
@ -214,7 +224,7 @@ public:
|
||||
// connections are closed automatically. The connections can be
|
||||
// re-established with a call to transceiver_online(true) assuming
|
||||
// the fault condition has been rectified or is transient.
|
||||
Q_SIGNAL void transceiver_failure (QString reason) const;
|
||||
Q_SIGNAL void transceiver_failure (QString const& reason) const;
|
||||
|
||||
private:
|
||||
class impl;
|
||||
|
@ -1045,6 +1045,9 @@ this setting allows you to select which audio input will be used
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="CAT_poll_interval_spin_box">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Interval to poll rig for status. Set to zero for no polling. Longer intervals will mean that changes to the rig will take longer to be detected.</p><p>If you set this to zero then spots may be uploaded with an incorrect frequency.</p></body></html></string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> s</string>
|
||||
</property>
|
||||
@ -1127,13 +1130,10 @@ radio interface behave as expected.</string>
|
||||
<string>Split Operation</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_12">
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="split_none_radio_button">
|
||||
<item row="0" column="2">
|
||||
<widget class="QRadioButton" name="split_emulate_radio_button">
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
<string>Fake It</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">split_mode_button_group</string>
|
||||
@ -1150,27 +1150,17 @@ radio interface behave as expected.</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QRadioButton" name="split_emulate_radio_button">
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="split_none_radio_button">
|
||||
<property name="text">
|
||||
<string>Fake It</string>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">split_mode_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="reset_split_check_box">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Reset split on program exit</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset split on exit</string>
|
||||
<string>None</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">split_mode_button_group</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -1388,12 +1378,6 @@ both here.</string>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="azel_path_group_box">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>56</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>AzEl Directory</string>
|
||||
</property>
|
||||
@ -1403,6 +1387,9 @@ both here.</string>
|
||||
<property name="text">
|
||||
<string>Location:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>azel_path_select_push_button</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@ -2476,8 +2463,8 @@ soundcard changes</string>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>254</x>
|
||||
<y>554</y>
|
||||
<x>272</x>
|
||||
<y>606</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
@ -2492,8 +2479,8 @@ soundcard changes</string>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>322</x>
|
||||
<y>554</y>
|
||||
<x>340</x>
|
||||
<y>606</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
@ -2508,7 +2495,7 @@ soundcard changes</string>
|
||||
<slot>setFocus()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>566</x>
|
||||
<x>404</x>
|
||||
<y>62</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
|
@ -39,8 +39,10 @@ void DXLabSuiteCommanderTransceiver::register_transceivers (TransceiverFactory::
|
||||
(*registry)[commander_transceiver_name] = TransceiverFactory::Capabilities {id, TransceiverFactory::Capabilities::network, true};
|
||||
}
|
||||
|
||||
DXLabSuiteCommanderTransceiver::DXLabSuiteCommanderTransceiver (std::unique_ptr<TransceiverBase> wrapped, QString const& address, bool use_for_ptt, int poll_interval)
|
||||
: PollingTransceiver {poll_interval}
|
||||
DXLabSuiteCommanderTransceiver::DXLabSuiteCommanderTransceiver (std::unique_ptr<TransceiverBase> wrapped,
|
||||
QString const& address, bool use_for_ptt,
|
||||
int poll_interval, QObject * parent)
|
||||
: PollingTransceiver {poll_interval, parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, use_for_ptt_ {use_for_ptt}
|
||||
, server_ {address}
|
||||
@ -48,14 +50,10 @@ DXLabSuiteCommanderTransceiver::DXLabSuiteCommanderTransceiver (std::unique_ptr<
|
||||
{
|
||||
}
|
||||
|
||||
DXLabSuiteCommanderTransceiver::~DXLabSuiteCommanderTransceiver ()
|
||||
int DXLabSuiteCommanderTransceiver::do_start ()
|
||||
{
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT ("starting");
|
||||
wrapped_->start ();
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "starting");
|
||||
if (wrapped_) wrapped_->start (0);
|
||||
|
||||
auto server_details = network_server_lookup (server_, 52002u, QHostAddress::LocalHost, QAbstractSocket::IPv4Protocol);
|
||||
|
||||
@ -67,11 +65,46 @@ void DXLabSuiteCommanderTransceiver::do_start ()
|
||||
commander_->connectToHost (std::get<0> (server_details), std::get<1> (server_details));
|
||||
if (!commander_->waitForConnected ())
|
||||
{
|
||||
TRACE_CAT ("failed to connect" << commander_->errorString ());
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed to connect" << commander_->errorString ());
|
||||
throw error {tr ("Failed to connect to DX Lab Suite Commander\n") + commander_->errorString ()};
|
||||
}
|
||||
|
||||
|
||||
int resolution {0};
|
||||
auto reply = command_with_reply ("<command:10>CmdGetFreq<parameters:0>");
|
||||
if (0 == reply.indexOf ("<CmdFreq:"))
|
||||
{
|
||||
auto f = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
|
||||
if (f && !(f % 10))
|
||||
{
|
||||
auto test_frequency = f - f % 100 + 55;
|
||||
auto f_string = frequency_to_string (test_frequency);
|
||||
auto params = ("<xcvrfreq:%1>" + f_string).arg (f_string.size ());
|
||||
simple_command (("<command:10>CmdSetFreq<parameters:%1>" + params).arg (params.size ()));
|
||||
reply = command_with_reply ("<command:10>CmdGetFreq<parameters:0>");
|
||||
if (0 == reply.indexOf ("<CmdFreq:"))
|
||||
{
|
||||
auto new_frequency = string_to_frequency (reply.mid (reply.indexOf ('>') + 1));
|
||||
switch (static_cast<Radio::FrequencyDelta> (new_frequency - test_frequency))
|
||||
{
|
||||
case -5: resolution = -1; break; // 10Hz truncated
|
||||
case 5: resolution = 1; break; // 10Hz rounded
|
||||
case -55: resolution = -2; break; // 100Hz truncated
|
||||
case 45: resolution = 2; break; // 100Hz rounded
|
||||
}
|
||||
f_string = frequency_to_string (f);
|
||||
params = ("<xcvrfreq:%1>" + f_string).arg (f_string.size ());
|
||||
simple_command (("<command:10>CmdSetFreq<parameters:%1>" + params).arg (params.size ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "get frequency unexpected response");
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly reading frequency")};
|
||||
}
|
||||
|
||||
poll ();
|
||||
return resolution;
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_stop ()
|
||||
@ -82,27 +115,30 @@ void DXLabSuiteCommanderTransceiver::do_stop ()
|
||||
delete commander_, commander_ = nullptr;
|
||||
}
|
||||
|
||||
wrapped_->stop ();
|
||||
TRACE_CAT ("stopped");
|
||||
if (wrapped_) wrapped_->stop ();
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "stopped");
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT (on << state ());
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", on << state ());
|
||||
if (use_for_ptt_)
|
||||
{
|
||||
simple_command (on ? "<command:5>CmdTX<parameters:0>" : "<command:5>CmdRX<parameters:0>");
|
||||
}
|
||||
else
|
||||
{
|
||||
wrapped_->ptt (on);
|
||||
Q_ASSERT (wrapped_);
|
||||
TransceiverState new_state {wrapped_->state ()};
|
||||
new_state.ptt (on);
|
||||
wrapped_->set (new_state, 0);
|
||||
}
|
||||
update_PTT (on);
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_frequency (Frequency f, MODE m)
|
||||
void DXLabSuiteCommanderTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT (f << state ());
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", f << state ());
|
||||
auto f_string = frequency_to_string (f);
|
||||
if (UNK != m)
|
||||
{
|
||||
@ -119,9 +155,9 @@ void DXLabSuiteCommanderTransceiver::do_frequency (Frequency f, MODE m)
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_tx_frequency (Frequency tx, bool /* rationalise_mode */)
|
||||
void DXLabSuiteCommanderTransceiver::do_tx_frequency (Frequency tx, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT (tx << state ());
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", tx << state ());
|
||||
if (tx)
|
||||
{
|
||||
auto f_string = frequency_to_string (tx);
|
||||
@ -136,9 +172,9 @@ void DXLabSuiteCommanderTransceiver::do_tx_frequency (Frequency tx, bool /* rati
|
||||
update_other_frequency (tx);
|
||||
}
|
||||
|
||||
void DXLabSuiteCommanderTransceiver::do_mode (MODE m, bool /* rationalise */)
|
||||
void DXLabSuiteCommanderTransceiver::do_mode (MODE m)
|
||||
{
|
||||
TRACE_CAT (m << state ());
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", m << state ());
|
||||
auto m_string = map_mode (m);
|
||||
auto params = ("<1:%1>" + m_string).arg (m_string.size ());
|
||||
simple_command (("<command:10>CmdSetMode<parameters:%1>" + params).arg (params.size ()));
|
||||
@ -168,7 +204,7 @@ void DXLabSuiteCommanderTransceiver::poll ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("get frequency unexpected response");
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get frequency unexpected response");
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling frequency")};
|
||||
}
|
||||
|
||||
@ -189,7 +225,7 @@ void DXLabSuiteCommanderTransceiver::poll ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("get tx frequency unexpected response");
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get tx frequency unexpected response");
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling TX frequency")};
|
||||
}
|
||||
}
|
||||
@ -208,13 +244,13 @@ void DXLabSuiteCommanderTransceiver::poll ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("unexpected split state" << split);
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected split state" << split);
|
||||
throw error {tr ("DX Lab Suite Commander sent an unrecognised split state: ") + split};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("get split mode unexpected response");
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "get split mode unexpected response");
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling split status")};
|
||||
}
|
||||
|
||||
@ -265,14 +301,14 @@ void DXLabSuiteCommanderTransceiver::poll ()
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("unexpected mode name" << mode);
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected mode name" << mode);
|
||||
throw error {tr ("DX Lab Suite Commander sent an unrecognised mode: \"") + mode + '"'};
|
||||
}
|
||||
update_mode (m);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("unexpected response");
|
||||
TRACE_CAT_POLL ("DXLabSuiteCommanderTransceiver", "unexpected response");
|
||||
throw error {tr ("DX Lab Suite Commander didn't respond correctly polling mode")};
|
||||
}
|
||||
}
|
||||
@ -283,12 +319,12 @@ void DXLabSuiteCommanderTransceiver::simple_command (QString const& cmd, bool no
|
||||
|
||||
if (!no_debug)
|
||||
{
|
||||
TRACE_CAT (cmd);
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd);
|
||||
}
|
||||
|
||||
if (!write_to_port (cmd))
|
||||
{
|
||||
TRACE_CAT ("failed:" << commander_->errorString ());
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed:" << commander_->errorString ());
|
||||
throw error {tr ("DX Lab Suite Commander send command failed\n") + commander_->errorString ()};
|
||||
}
|
||||
}
|
||||
@ -299,7 +335,7 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd,
|
||||
|
||||
if (!write_to_port (cmd))
|
||||
{
|
||||
TRACE_CAT ("failed to send command:" << commander_->errorString ());
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", "failed to send command:" << commander_->errorString ());
|
||||
throw error {
|
||||
tr ("DX Lab Suite Commander failed to send command \"%1\": %2\n")
|
||||
.arg (cmd)
|
||||
@ -316,7 +352,7 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd,
|
||||
replied = commander_->waitForReadyRead ();
|
||||
if (!replied && commander_->error () != commander_->SocketTimeoutError)
|
||||
{
|
||||
TRACE_CAT (cmd << "failed to read reply:" << commander_->errorString ());
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "failed to read reply:" << commander_->errorString ());
|
||||
throw error {
|
||||
tr ("DX Lab Suite Commander send command \"%1\" read reply failed: %2\n")
|
||||
.arg (cmd)
|
||||
@ -327,7 +363,7 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd,
|
||||
|
||||
if (!replied)
|
||||
{
|
||||
TRACE_CAT (cmd << "retries exhausted");
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "retries exhausted");
|
||||
throw error {
|
||||
tr ("DX Lab Suite Commander retries exhausted sending command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -343,7 +379,7 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd,
|
||||
|
||||
if (!no_debug)
|
||||
{
|
||||
TRACE_CAT (cmd << "->" << result);
|
||||
TRACE_CAT ("DXLabSuiteCommanderTransceiver", cmd << "->" << result);
|
||||
}
|
||||
|
||||
return result; // converting raw UTF-8 bytes to QString
|
||||
|
@ -27,15 +27,16 @@ public:
|
||||
static void register_transceivers (TransceiverFactory::Transceivers *, int id);
|
||||
|
||||
// takes ownership of wrapped Transceiver
|
||||
explicit DXLabSuiteCommanderTransceiver (std::unique_ptr<TransceiverBase> wrapped, QString const& address, bool use_for_ptt, int poll_interval);
|
||||
~DXLabSuiteCommanderTransceiver ();
|
||||
explicit DXLabSuiteCommanderTransceiver (std::unique_ptr<TransceiverBase> wrapped,
|
||||
QString const& address, bool use_for_ptt,
|
||||
int poll_interval, QObject * parent = nullptr);
|
||||
|
||||
protected:
|
||||
void do_start () override;
|
||||
int do_start () override;
|
||||
void do_stop () override;
|
||||
void do_frequency (Frequency, MODE) override;
|
||||
void do_tx_frequency (Frequency, bool rationalise_mode) override;
|
||||
void do_mode (MODE, bool rationalise) override;
|
||||
void do_frequency (Frequency, MODE, bool no_ignore) override;
|
||||
void do_tx_frequency (Frequency, bool no_ignore) override;
|
||||
void do_mode (MODE) override;
|
||||
void do_ptt (bool on) override;
|
||||
|
||||
void poll () override;
|
||||
@ -47,7 +48,7 @@ private:
|
||||
QString frequency_to_string (Frequency) const;
|
||||
Frequency string_to_frequency (QString) const;
|
||||
|
||||
std::unique_ptr<TransceiverBase> wrapped_;
|
||||
std::unique_ptr<TransceiverBase> wrapped_; // may be null
|
||||
bool use_for_ptt_;
|
||||
QString server_;
|
||||
QTcpSocket * commander_;
|
||||
|
@ -1,116 +1,65 @@
|
||||
#include "EmulateSplitTransceiver.hpp"
|
||||
|
||||
EmulateSplitTransceiver::EmulateSplitTransceiver (std::unique_ptr<Transceiver> wrapped)
|
||||
: wrapped_ {std::move (wrapped)}
|
||||
, frequency_ {0, 0}
|
||||
, pre_tx_frequency_ {0}
|
||||
, tx_ {false}
|
||||
EmulateSplitTransceiver::EmulateSplitTransceiver (std::unique_ptr<Transceiver> wrapped, QObject * parent)
|
||||
: Transceiver {parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, rx_frequency_ {0}
|
||||
, tx_frequency_ {0}
|
||||
, split_ {false}
|
||||
{
|
||||
// Connect update signal of wrapped Transceiver object instance to ours.
|
||||
connect (wrapped_.get (), &Transceiver::update, this, &EmulateSplitTransceiver::handle_update);
|
||||
|
||||
// Connect failure signal of wrapped Transceiver object to our
|
||||
// parent failure signal.
|
||||
// Connect other signals of wrapped Transceiver object to our
|
||||
// parent matching signals.
|
||||
connect (wrapped_.get (), &Transceiver::resolution, this, &Transceiver::resolution);
|
||||
connect (wrapped_.get (), &Transceiver::finished, this, &Transceiver::finished);
|
||||
connect (wrapped_.get (), &Transceiver::failure, this, &Transceiver::failure);
|
||||
}
|
||||
|
||||
void EmulateSplitTransceiver::start () noexcept
|
||||
{
|
||||
wrapped_->start ();
|
||||
wrapped_->tx_frequency (0, false);
|
||||
}
|
||||
|
||||
void EmulateSplitTransceiver::frequency (Frequency rx, MODE m) noexcept
|
||||
void EmulateSplitTransceiver::set (TransceiverState const& s, unsigned sequence_number) noexcept
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "EmulateSplitTransceiver::frequency:" << rx << "mode:" << m;
|
||||
qDebug () << "EmulateSplitTransceiver::set: state:" << s << "#:" << sequence_number;
|
||||
#endif
|
||||
// save for use in updates
|
||||
rx_frequency_ = s.frequency ();
|
||||
tx_frequency_ = s.tx_frequency ();
|
||||
split_ = s.split ();
|
||||
|
||||
// Save frequency parameters.
|
||||
frequency_[0] = rx;
|
||||
|
||||
// Set active frequency.
|
||||
wrapped_->frequency (rx, m);
|
||||
TransceiverState emulated_state {s};
|
||||
if (s.ptt () && split_) emulated_state.frequency (s.tx_frequency ());
|
||||
emulated_state.split (false);
|
||||
emulated_state.tx_frequency (0);
|
||||
wrapped_->set (emulated_state, sequence_number);
|
||||
}
|
||||
|
||||
void EmulateSplitTransceiver::tx_frequency (Frequency tx, bool /* rationalise_mode */) noexcept
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "EmulateSplitTransceiver::tx_frequency:" << tx;
|
||||
#endif
|
||||
|
||||
// Save frequency parameter.
|
||||
frequency_[1] = tx;
|
||||
|
||||
// Set active frequency.
|
||||
wrapped_->frequency (frequency_[(tx_ && frequency_[1]) ? 1 : 0]);
|
||||
}
|
||||
|
||||
void EmulateSplitTransceiver::ptt (bool on) noexcept
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "EmulateSplitTransceiver::ptt:" << on;
|
||||
#endif
|
||||
|
||||
// Save TX state for future frequency change requests.
|
||||
if (on)
|
||||
{
|
||||
// save the Rx frequency
|
||||
pre_tx_frequency_ = frequency_[0];
|
||||
|
||||
// Switch to other frequency if we have one i.e. client wants
|
||||
// split operation).
|
||||
wrapped_->frequency (frequency_[frequency_[1] ? 1 : 0]);
|
||||
|
||||
// Change TX state.
|
||||
wrapped_->ptt (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Change TX state.
|
||||
wrapped_->ptt (false);
|
||||
|
||||
// Switch to RX frequency.
|
||||
wrapped_->frequency (pre_tx_frequency_);
|
||||
pre_tx_frequency_ = 0;
|
||||
}
|
||||
tx_ = on;
|
||||
}
|
||||
|
||||
void EmulateSplitTransceiver::handle_update (TransceiverState state)
|
||||
void EmulateSplitTransceiver::handle_update (TransceiverState const& state,
|
||||
unsigned sequence_number)
|
||||
{
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "EmulateSplitTransceiver::handle_update: from wrapped:" << state;
|
||||
#endif
|
||||
|
||||
// Change to reflect emulated state, we don't want to report the
|
||||
// shifted frequency when transmitting.
|
||||
if (pre_tx_frequency_)
|
||||
{
|
||||
state.frequency (pre_tx_frequency_);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Follow the rig if in RX mode.
|
||||
frequency_[0] = state.frequency ();
|
||||
}
|
||||
|
||||
// Always report the other frequency as the Tx frequency we will use.
|
||||
state.tx_frequency (frequency_[1]);
|
||||
|
||||
if (state.split ())
|
||||
{
|
||||
Q_EMIT failure (tr ("Emulated split mode requires rig to be in simplex mode"));
|
||||
}
|
||||
else
|
||||
{
|
||||
state.split (true); // override rig state
|
||||
|
||||
TransceiverState new_state {state};
|
||||
// Follow the rig if in RX mode.
|
||||
if (state.ptt ()) new_state.frequency (rx_frequency_);
|
||||
|
||||
// These are always what was requested in prior set state operation
|
||||
new_state.tx_frequency (tx_frequency_);
|
||||
new_state.split (split_);
|
||||
|
||||
#if WSJT_TRACE_CAT
|
||||
qDebug () << "EmulateSplitTransceiver::handle_update: signalling:" << state;
|
||||
#endif
|
||||
|
||||
// signal emulated state
|
||||
Q_EMIT update (state);
|
||||
Q_EMIT update (new_state, sequence_number);
|
||||
}
|
||||
}
|
||||
|
@ -29,25 +29,23 @@ class EmulateSplitTransceiver final
|
||||
{
|
||||
public:
|
||||
// takes ownership of wrapped Transceiver
|
||||
explicit EmulateSplitTransceiver (std::unique_ptr<Transceiver> wrapped);
|
||||
explicit EmulateSplitTransceiver (std::unique_ptr<Transceiver> wrapped,
|
||||
QObject * parent = nullptr);
|
||||
|
||||
void start () noexcept override;
|
||||
void frequency (Frequency, MODE) noexcept override;
|
||||
void tx_frequency (Frequency, bool rationalise_mode) noexcept override;
|
||||
void ptt (bool on) noexcept override;
|
||||
void set (TransceiverState const&,
|
||||
unsigned sequence_number) noexcept override;
|
||||
|
||||
// forward everything else to wrapped Transceiver
|
||||
void stop (bool /* reset_split */) noexcept override {wrapped_->stop (false); Q_EMIT finished ();}
|
||||
void mode (MODE m, bool /* rationalise */) noexcept override {wrapped_->mode (m, false);}
|
||||
void sync (bool force_signal) noexcept override {wrapped_->sync (force_signal);}
|
||||
void start (unsigned sequence_number) noexcept override {wrapped_->start (sequence_number);}
|
||||
void stop () noexcept override {wrapped_->stop ();}
|
||||
|
||||
private:
|
||||
void handle_update (TransceiverState);
|
||||
void handle_update (TransceiverState const&, unsigned seqeunce_number);
|
||||
|
||||
std::unique_ptr<Transceiver> wrapped_;
|
||||
Frequency frequency_[2]; // [0] <- RX, [1] <- other
|
||||
Frequency pre_tx_frequency_; // return to this on switching to Rx
|
||||
bool tx_;
|
||||
Frequency rx_frequency_; // requested Rx frequency
|
||||
Frequency tx_frequency_; // requested Tx frequency
|
||||
bool split_; // requested split state
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -72,10 +72,13 @@ qint32 const HRDMessage::magic_2_value_ (0xABCD1234);
|
||||
HRDTransceiver::HRDTransceiver (std::unique_ptr<TransceiverBase> wrapped
|
||||
, QString const& server
|
||||
, bool use_for_ptt
|
||||
, int poll_interval)
|
||||
: PollingTransceiver {poll_interval}
|
||||
, int poll_interval
|
||||
, bool set_rig_mode
|
||||
, QObject * parent)
|
||||
: PollingTransceiver {poll_interval, parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, use_for_ptt_ {use_for_ptt}
|
||||
, set_rig_mode_ {set_rig_mode}
|
||||
, server_ {server}
|
||||
, hrd_ {0}
|
||||
, protocol_ {none}
|
||||
@ -102,14 +105,10 @@ HRDTransceiver::HRDTransceiver (std::unique_ptr<TransceiverBase> wrapped
|
||||
{
|
||||
}
|
||||
|
||||
HRDTransceiver::~HRDTransceiver ()
|
||||
int HRDTransceiver::do_start ()
|
||||
{
|
||||
}
|
||||
|
||||
void HRDTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT ("starting");
|
||||
wrapped_->start ();
|
||||
TRACE_CAT ("HRDTransceiver", "starting");
|
||||
if (wrapped_) wrapped_->start (0);
|
||||
|
||||
auto server_details = network_server_lookup (server_, 7809u);
|
||||
if (!hrd_)
|
||||
@ -119,7 +118,7 @@ void HRDTransceiver::do_start ()
|
||||
hrd_->connectToHost (std::get<0> (server_details), std::get<1> (server_details));
|
||||
if (!hrd_->waitForConnected ())
|
||||
{
|
||||
TRACE_CAT ("failed to connect:" << hrd_->errorString ());
|
||||
TRACE_CAT ("HRDTransceiver", "failed to connect:" << hrd_->errorString ());
|
||||
throw error {tr ("Failed to connect to Ham Radio Deluxe\n") + hrd_->errorString ()};
|
||||
}
|
||||
|
||||
@ -144,7 +143,7 @@ void HRDTransceiver::do_start ()
|
||||
hrd_->connectToHost (std::get<0> (server_details), std::get<1> (server_details));
|
||||
if (!hrd_->waitForConnected ())
|
||||
{
|
||||
TRACE_CAT ("failed to connect:" << hrd_->errorString ());
|
||||
TRACE_CAT ("HRDTransceiver", "failed to connect:" << hrd_->errorString ());
|
||||
throw error {tr ("Failed to connect to Ham Radio Deluxe\n") + hrd_->errorString ()};
|
||||
}
|
||||
|
||||
@ -161,14 +160,14 @@ void HRDTransceiver::do_start ()
|
||||
auto id = send_command ("get id", false, false);
|
||||
auto version = send_command ("get version", false, false);
|
||||
|
||||
TRACE_CAT ("Id:" << id << "Version:" << version);
|
||||
TRACE_CAT ("HRDTransceiver", "Id:" << id << "Version:" << version);
|
||||
HRD_info << "Id: " << id << "\n";
|
||||
HRD_info << "Version: " << version << "\n";
|
||||
|
||||
auto radios = send_command ("get radios", false, false).trimmed ().split (',', QString::SkipEmptyParts);
|
||||
if (radios.isEmpty ())
|
||||
{
|
||||
TRACE_CAT ("no rig found");
|
||||
TRACE_CAT ("HRDTransceiver", "no rig found");
|
||||
throw error {tr ("Ham Radio Deluxe: no rig found")};
|
||||
}
|
||||
|
||||
@ -181,10 +180,10 @@ void HRDTransceiver::do_start ()
|
||||
}
|
||||
|
||||
#if WSJT_TRACE_CAT
|
||||
TRACE_CAT ("radios:-");
|
||||
TRACE_CAT ("HRDTransceiver", "radios:-");
|
||||
Q_FOREACH (auto const& radio, radios_)
|
||||
{
|
||||
TRACE_CAT ("\t[" << std::get<0> (radio) << "] " << std::get<1> (radio));
|
||||
TRACE_CAT ("HRDTransceiver", "\t[" << std::get<0> (radio) << "] " << std::get<1> (radio));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -192,36 +191,36 @@ void HRDTransceiver::do_start ()
|
||||
HRD_info << "Current radio: " << current_radio_name << "\n";
|
||||
if (current_radio_name.isEmpty ())
|
||||
{
|
||||
TRACE_CAT ("no rig found");
|
||||
TRACE_CAT ("HRDTransceiver", "no rig found");
|
||||
throw error {tr ("Ham Radio Deluxe: no rig found")};
|
||||
}
|
||||
|
||||
vfo_count_ = send_command ("get vfo-count").toUInt ();
|
||||
HRD_info << "VFO count: " << vfo_count_ << "\n";
|
||||
TRACE_CAT ("vfo count:" << vfo_count_);
|
||||
TRACE_CAT ("HRDTransceiver", "vfo count:" << vfo_count_);
|
||||
|
||||
buttons_ = send_command ("get buttons").trimmed ().split (',', QString::SkipEmptyParts).replaceInStrings (" ", "~");
|
||||
TRACE_CAT ("HRD Buttons: " << buttons_);
|
||||
TRACE_CAT ("HRDTransceiver", "HRD Buttons: " << buttons_);
|
||||
HRD_info << "Buttons: {" << buttons_.join (", ") << "}\n";
|
||||
|
||||
dropdown_names_ = send_command ("get dropdowns").trimmed ().split (',', QString::SkipEmptyParts);
|
||||
TRACE_CAT ("Dropdowns:");
|
||||
TRACE_CAT ("HRDTransceiver", "Dropdowns:");
|
||||
HRD_info << "Dropdowns:\n";
|
||||
Q_FOREACH (auto const& dd, dropdown_names_)
|
||||
{
|
||||
auto selections = send_command ("get dropdown-list {" + dd + "}").trimmed ().split (',', QString::SkipEmptyParts);
|
||||
TRACE_CAT ("\t" << dd << ": {" << selections.join (", ") << "}");
|
||||
TRACE_CAT ("HRDTransceiver", "\t" << dd << ": {" << selections.join (", ") << "}");
|
||||
HRD_info << "\t" << dd << ": {" << selections.join (", ") << "}\n";
|
||||
dropdowns_[dd] = selections;
|
||||
}
|
||||
|
||||
slider_names_ = send_command ("get sliders").trimmed ().split (',', QString::SkipEmptyParts).replaceInStrings (" ", "~");
|
||||
TRACE_CAT ("Sliders:-");
|
||||
TRACE_CAT ("HRDTransceiver", "Sliders:-");
|
||||
HRD_info << "Sliders:\n";
|
||||
Q_FOREACH (auto const& s, slider_names_)
|
||||
{
|
||||
auto range = send_command ("get slider-range " + current_radio_name + " " + s).trimmed ().split (',', QString::SkipEmptyParts);
|
||||
TRACE_CAT ("\t" << s << ": {" << range.join (", ") << "}");
|
||||
TRACE_CAT ("HRDTransceiver", "\t" << s << ": {" << range.join (", ") << "}");
|
||||
HRD_info << "\t" << s << ": {" << range.join (", ") << "}\n";
|
||||
sliders_[s] = range;
|
||||
}
|
||||
@ -292,6 +291,24 @@ void HRDTransceiver::do_start ()
|
||||
update_mode (lookup_mode (get_dropdown (mode_A_dropdown_), mode_A_map_));
|
||||
}
|
||||
}
|
||||
|
||||
int resolution {0};
|
||||
auto f = send_command ("get frequency").toUInt ();
|
||||
if (f && !(f % 10))
|
||||
{
|
||||
auto test_frequency = f - f % 100 + 55;
|
||||
send_simple_command ("set frequency-hz " + QString::number (test_frequency));
|
||||
auto new_frequency = send_command ("get frequency").toUInt ();
|
||||
switch (static_cast<Radio::FrequencyDelta> (new_frequency - test_frequency))
|
||||
{
|
||||
case -5: resolution = -1; break; // 10Hz truncated
|
||||
case 5: resolution = 1; break; // 10Hz rounded
|
||||
case -55: resolution = -2; break; // 100Hz truncated
|
||||
case 45: resolution = 2; break; // 100Hz rounded
|
||||
}
|
||||
send_simple_command ("set frequency-hz " + QString::number (f));
|
||||
}
|
||||
return resolution;
|
||||
}
|
||||
|
||||
void HRDTransceiver::do_stop ()
|
||||
@ -301,11 +318,8 @@ void HRDTransceiver::do_stop ()
|
||||
hrd_->close ();
|
||||
}
|
||||
|
||||
if (wrapped_)
|
||||
{
|
||||
wrapped_->stop ();
|
||||
}
|
||||
TRACE_CAT ("stopped" << state () << "reversed" << reversed_);
|
||||
if (wrapped_) wrapped_->stop ();
|
||||
TRACE_CAT ("HRDTransceiver", "stopped" << state () << "reversed" << reversed_);
|
||||
}
|
||||
|
||||
int HRDTransceiver::find_button (QRegExp const& re) const
|
||||
@ -352,11 +366,11 @@ void HRDTransceiver::map_modes (int dropdown, ModeMap *map)
|
||||
map->push_back (std::forward_as_tuple (DIG_FM, find_dropdown_selection (dropdown, QRegExp ("^(PKT-FM|PKT|FM)$"))));
|
||||
|
||||
#if WSJT_TRACE_CAT
|
||||
TRACE_CAT ("for dropdown" << dropdown_names_[dropdown]);
|
||||
TRACE_CAT ("HRDTransceiver", "for dropdown" << dropdown_names_[dropdown]);
|
||||
std::for_each (map->begin (), map->end (), [this, dropdown] (ModeMap::value_type const& item)
|
||||
{
|
||||
auto const& rhs = std::get<1> (item);
|
||||
TRACE_CAT ('\t' << std::get<0> (item) << "<->" << (rhs.size () ? dropdowns_[dropdown_names_[dropdown]][rhs.front ()] : "None"));
|
||||
TRACE_CAT ("HRDTransceiver", '\t' << std::get<0> (item) << "<->" << (rhs.size () ? dropdowns_[dropdown_names_[dropdown]][rhs.front ()] : "None"));
|
||||
});
|
||||
#endif
|
||||
}
|
||||
@ -419,14 +433,14 @@ void HRDTransceiver::set_dropdown (int dd, int value)
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("item" << value << "not found in" << dd_name);
|
||||
TRACE_CAT ("HRDTransceiver", "item" << value << "not found in" << dd_name);
|
||||
throw error {tr ("Ham Radio Deluxe: item not found in %1 dropdown list").arg (dd_name)};
|
||||
}
|
||||
}
|
||||
|
||||
void HRDTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT (on);
|
||||
TRACE_CAT ("HRDTransceiver", on);
|
||||
if (use_for_ptt_)
|
||||
{
|
||||
if (ptt_button_ >= 0)
|
||||
@ -439,7 +453,10 @@ void HRDTransceiver::do_ptt (bool on)
|
||||
}
|
||||
else
|
||||
{
|
||||
wrapped_->ptt (on);
|
||||
Q_ASSERT (wrapped_);
|
||||
TransceiverState new_state {wrapped_->state ()};
|
||||
new_state.ptt (on);
|
||||
wrapped_->set (new_state, 0);
|
||||
}
|
||||
update_PTT (on);
|
||||
}
|
||||
@ -456,17 +473,17 @@ void HRDTransceiver::set_button (int button_index, bool checked)
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("invalid button");
|
||||
TRACE_CAT ("HRDTransceiver", "invalid button");
|
||||
throw error {tr ("Ham Radio Deluxe: button not available")};
|
||||
}
|
||||
}
|
||||
|
||||
void HRDTransceiver::do_frequency (Frequency f, MODE m)
|
||||
void HRDTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT (f << "reversed" << reversed_);
|
||||
TRACE_CAT ("HRDTransceiver", f << "reversed" << reversed_);
|
||||
if (UNK != m)
|
||||
{
|
||||
do_mode (m, false);
|
||||
do_mode (m);
|
||||
}
|
||||
auto fo_string = QString::number (f);
|
||||
if (vfo_count_ > 1 && reversed_)
|
||||
@ -481,9 +498,9 @@ void HRDTransceiver::do_frequency (Frequency f, MODE m)
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
|
||||
void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode)
|
||||
void HRDTransceiver::do_tx_frequency (Frequency tx, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT (tx << "rationalize mode:" << rationalise_mode << "reversed" << reversed_);
|
||||
TRACE_CAT ("HRDTransceiver", tx << "reversed" << reversed_);
|
||||
|
||||
// re-check if reversed VFOs
|
||||
bool rx_A {true};
|
||||
@ -510,7 +527,7 @@ void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode)
|
||||
bool split {tx != 0};
|
||||
if (split)
|
||||
{
|
||||
if (rationalise_mode)
|
||||
if (set_rig_mode_)
|
||||
{
|
||||
if (!reversed_ && mode_B_dropdown_ >= 0)
|
||||
{
|
||||
@ -536,12 +553,13 @@ void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode)
|
||||
set_dropdown (mode_A_dropdown_, lookup_mode (state ().mode (), mode_A_map_));
|
||||
set_dropdown (receiver_dropdown_, (reversed_ ? rx_B_selection_ : rx_A_selection_).front ());
|
||||
}
|
||||
else
|
||||
else if (vfo_count_ > 1)
|
||||
{
|
||||
set_button (vfo_A_button_ >= 0 ? (reversed_ ? vfo_A_button_ : vfo_B_button_) : vfo_toggle_button_);
|
||||
set_dropdown (mode_A_dropdown_, lookup_mode (state ().mode (), mode_A_map_));
|
||||
set_button (vfo_A_button_ >= 0 ? (reversed_ ? vfo_B_button_ : vfo_A_button_) : vfo_toggle_button_);
|
||||
}
|
||||
// else Tx VFO mode gets set with frequency below
|
||||
}
|
||||
}
|
||||
|
||||
@ -565,12 +583,11 @@ void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode)
|
||||
// we rationalise the modes here as well as the frequencies
|
||||
set_button (vfo_B_button_ >= 0 ? vfo_B_button_ : vfo_toggle_button_);
|
||||
send_simple_command ("set frequency-hz " + fo_string);
|
||||
if (rationalise_mode && mode_B_dropdown_ < 0)
|
||||
if (set_rig_mode_ && mode_B_dropdown_ < 0)
|
||||
{
|
||||
// do this here rather than later so we only
|
||||
// toggle/switch VFOs once
|
||||
set_dropdown (mode_A_dropdown_, lookup_mode (state ().mode (), mode_A_map_));
|
||||
rationalise_mode = false;
|
||||
}
|
||||
set_button (vfo_A_button_ >= 0 ? vfo_A_button_ : vfo_toggle_button_);
|
||||
}
|
||||
@ -637,9 +654,9 @@ void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode)
|
||||
update_split (split);
|
||||
}
|
||||
|
||||
void HRDTransceiver::do_mode (MODE mode, bool rationalise)
|
||||
void HRDTransceiver::do_mode (MODE mode)
|
||||
{
|
||||
TRACE_CAT (mode);
|
||||
TRACE_CAT ("HRDTransceiver", mode);
|
||||
if (reversed_ && mode_B_dropdown_ >= 0)
|
||||
{
|
||||
set_dropdown (mode_B_dropdown_, lookup_mode (mode, mode_B_map_));
|
||||
@ -648,7 +665,7 @@ void HRDTransceiver::do_mode (MODE mode, bool rationalise)
|
||||
{
|
||||
set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_));
|
||||
}
|
||||
if (rationalise && state ().split ()) // rationalise mode if split
|
||||
if (set_rig_mode_ && state ().split ()) // rationalise mode if split
|
||||
{
|
||||
if (reversed_)
|
||||
{
|
||||
@ -672,12 +689,15 @@ void HRDTransceiver::do_mode (MODE mode, bool rationalise)
|
||||
set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_));
|
||||
set_dropdown (receiver_dropdown_, rx_B_selection_.front ());
|
||||
}
|
||||
else
|
||||
else if (vfo_count_ > 1)
|
||||
{
|
||||
set_button (vfo_A_button_ >= 0 ? vfo_A_button_ : vfo_toggle_button_);
|
||||
set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_));
|
||||
set_button (vfo_B_button_ >= 0 ? vfo_B_button_ : vfo_toggle_button_);
|
||||
}
|
||||
// else Tx VFO mode gets set when Tx VFO frequency is
|
||||
// set
|
||||
|
||||
if ( tx_A_button_ >= 0)
|
||||
{
|
||||
set_button (tx_A_button_);
|
||||
@ -706,12 +726,15 @@ void HRDTransceiver::do_mode (MODE mode, bool rationalise)
|
||||
set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_));
|
||||
set_dropdown (receiver_dropdown_, rx_A_selection_.front ());
|
||||
}
|
||||
else
|
||||
else if (vfo_count_ > 1)
|
||||
{
|
||||
set_button (vfo_B_button_ >= 0 ? vfo_B_button_ : vfo_toggle_button_);
|
||||
set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_));
|
||||
set_button (vfo_A_button_ >= 0 ? vfo_A_button_ : vfo_toggle_button_);
|
||||
}
|
||||
// else Tx VFO mode gets set when Tx VFO frequency is
|
||||
// set
|
||||
|
||||
if ( tx_B_button_ >= 0)
|
||||
{
|
||||
set_button (tx_B_button_);
|
||||
@ -732,7 +755,7 @@ bool HRDTransceiver::is_button_checked (int button_index, bool no_debug)
|
||||
auto reply = send_command ("get button-select " + buttons_.value (button_index), no_debug);
|
||||
if ("1" != reply && "0" != reply)
|
||||
{
|
||||
TRACE_CAT ("bad response");
|
||||
TRACE_CAT ("HRDTransceiver", "bad response");
|
||||
throw error {tr ("Ham Radio Deluxe didn't respond as expected")};
|
||||
}
|
||||
return "1" == reply;
|
||||
@ -859,7 +882,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
});
|
||||
if (radio_iter == radios_.end ())
|
||||
{
|
||||
TRACE_CAT ("rig disappeared or changed");
|
||||
TRACE_CAT ("HRDTransceiver", "rig disappeared or changed");
|
||||
throw error {tr ("Ham Radio Deluxe: rig has disappeared or changed")};
|
||||
}
|
||||
|
||||
@ -873,7 +896,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
|
||||
if (QTcpSocket::ConnectedState != hrd_->state ())
|
||||
{
|
||||
TRACE_CAT (cmd << "failed" << hrd_->errorString ());
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "failed" << hrd_->errorString ());
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe send command \"%1\" failed %2\n")
|
||||
.arg (cmd)
|
||||
@ -886,7 +909,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
auto message = ((prepend_context ? context + cmd : cmd) + "\r").toLocal8Bit ();
|
||||
if (!write_to_port (message.constData (), message.size ()))
|
||||
{
|
||||
TRACE_CAT ("failed to write command" << cmd << "to HRD");
|
||||
TRACE_CAT ("HRDTransceiver", "failed to write command" << cmd << "to HRD");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe: failed to write command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -899,7 +922,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
QScopedPointer<HRDMessage> message {new (string) HRDMessage};
|
||||
if (!write_to_port (reinterpret_cast<char const *> (message.data ()), message->size_))
|
||||
{
|
||||
TRACE_CAT ("failed to write command" << cmd << "to HRD");
|
||||
TRACE_CAT ("HRDTransceiver", "failed to write command" << cmd << "to HRD");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe: failed to write command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -916,7 +939,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
HRDMessage const * reply {new (buffer) HRDMessage};
|
||||
if (reply->magic_1_value_ != reply->magic_1_ && reply->magic_2_value_ != reply->magic_2_)
|
||||
{
|
||||
TRACE_CAT (cmd << "invalid reply");
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "invalid reply");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe sent an invalid reply to our command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -928,7 +951,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
{
|
||||
if (!no_debug)
|
||||
{
|
||||
TRACE_CAT (cmd << "reading more reply data");
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "reading more reply data");
|
||||
}
|
||||
buffer += read_reply (cmd);
|
||||
reply = new (buffer) HRDMessage;
|
||||
@ -938,7 +961,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr
|
||||
}
|
||||
if (!no_debug)
|
||||
{
|
||||
TRACE_CAT (cmd << " ->" << result);
|
||||
TRACE_CAT ("HRDTransceiver", cmd << " ->" << result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -970,7 +993,7 @@ QByteArray HRDTransceiver::read_reply (QString const& cmd)
|
||||
replied = hrd_->waitForReadyRead ();
|
||||
if (!replied && hrd_->error () != hrd_->SocketTimeoutError)
|
||||
{
|
||||
TRACE_CAT (cmd << "failed to reply" << hrd_->errorString ());
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "failed to reply" << hrd_->errorString ());
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe failed to reply to command \"%1\" %2\n")
|
||||
.arg (cmd)
|
||||
@ -980,7 +1003,7 @@ QByteArray HRDTransceiver::read_reply (QString const& cmd)
|
||||
}
|
||||
if (!replied)
|
||||
{
|
||||
TRACE_CAT (cmd << "retries exhausted");
|
||||
TRACE_CAT ("HRDTransceiver", cmd << "retries exhausted");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe retries exhausted sending command \"%1\"")
|
||||
.arg (cmd)
|
||||
@ -993,7 +1016,7 @@ void HRDTransceiver::send_simple_command (QString const& command, bool no_debug)
|
||||
{
|
||||
if ("OK" != send_command (command, no_debug))
|
||||
{
|
||||
TRACE_CAT (command << "unexpected response");
|
||||
TRACE_CAT ("HRDTransceiver", command << "unexpected response");
|
||||
throw error {
|
||||
tr ("Ham Radio Deluxe didn't respond to command \"%1\" as expected")
|
||||
.arg (command)
|
||||
|
@ -34,16 +34,17 @@ public:
|
||||
explicit HRDTransceiver (std::unique_ptr<TransceiverBase> wrapped
|
||||
, QString const& server
|
||||
, bool use_for_ptt
|
||||
, int poll_interval);
|
||||
~HRDTransceiver ();
|
||||
, int poll_interval
|
||||
, bool set_rig_mode
|
||||
, QObject * parent = nullptr);
|
||||
|
||||
protected:
|
||||
// Implement the TransceiverBase interface.
|
||||
void do_start () override;
|
||||
int do_start () override;
|
||||
void do_stop () override;
|
||||
void do_frequency (Frequency, MODE) override;
|
||||
void do_tx_frequency (Frequency, bool rationalise_mode) override;
|
||||
void do_mode (MODE, bool rationalise) override;
|
||||
void do_frequency (Frequency, MODE, bool no_ignore) override;
|
||||
void do_tx_frequency (Frequency, bool no_ignore) override;
|
||||
void do_mode (MODE) override;
|
||||
void do_ptt (bool on) override;
|
||||
|
||||
// Implement the PollingTransceiver interface.
|
||||
@ -74,10 +75,12 @@ private:
|
||||
|
||||
// An alternate TransceiverBase instance that can be used to drive
|
||||
// PTT if required.
|
||||
std::unique_ptr<TransceiverBase> wrapped_;
|
||||
std::unique_ptr<TransceiverBase> wrapped_; // may be null
|
||||
|
||||
bool use_for_ptt_; // Use HRD for PTT.
|
||||
|
||||
bool set_rig_mode_; // Set VFO mode when required
|
||||
|
||||
QString server_; // The TCP/IP addrress and port for
|
||||
// the HRD server.
|
||||
|
||||
|
@ -169,10 +169,13 @@ void HamlibTransceiver::RIGDeleter::cleanup (RIG * rig)
|
||||
}
|
||||
}
|
||||
|
||||
HamlibTransceiver::HamlibTransceiver (TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port)
|
||||
: PollingTransceiver {0}
|
||||
HamlibTransceiver::HamlibTransceiver (TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port,
|
||||
QObject * parent)
|
||||
: PollingTransceiver {0, parent}
|
||||
, rig_ {rig_init (RIG_MODEL_DUMMY)}
|
||||
, set_rig_mode_ {false}
|
||||
, back_ptt_port_ {false}
|
||||
, one_VFO_ {false}
|
||||
, is_dummy_ {true}
|
||||
, reversed_ {false}
|
||||
, mode_query_works_ {true}
|
||||
@ -218,10 +221,13 @@ HamlibTransceiver::HamlibTransceiver (TransceiverFactory::PTTMethod ptt_type, QS
|
||||
}
|
||||
}
|
||||
|
||||
HamlibTransceiver::HamlibTransceiver (int model_number, TransceiverFactory::ParameterPack const& params)
|
||||
: PollingTransceiver {params.poll_interval}
|
||||
HamlibTransceiver::HamlibTransceiver (int model_number, TransceiverFactory::ParameterPack const& params,
|
||||
QObject * parent)
|
||||
: PollingTransceiver {params.poll_interval, parent}
|
||||
, rig_ {rig_init (model_number)}
|
||||
, set_rig_mode_ {params.set_rig_mode}
|
||||
, back_ptt_port_ {TransceiverFactory::TX_audio_source_rear == params.audio_source}
|
||||
, one_VFO_ {false}
|
||||
, is_dummy_ {RIG_MODEL_DUMMY == model_number}
|
||||
, reversed_ {false}
|
||||
, mode_query_works_ {rig_ && rig_->caps->get_mode}
|
||||
@ -249,44 +255,44 @@ HamlibTransceiver::HamlibTransceiver (int model_number, TransceiverFactory::Para
|
||||
, "hamlib_settings.json");
|
||||
if (!settings_file_name.isEmpty ())
|
||||
{
|
||||
QFile settings_file {settings_file_name};
|
||||
if (settings_file.open (QFile::ReadOnly))
|
||||
{
|
||||
QJsonParseError status;
|
||||
auto settings_doc = QJsonDocument::fromJson (settings_file.readAll (), &status);
|
||||
if (status.error)
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: %1 at character offset %2")
|
||||
.arg (status.errorString ()).arg (status.offset)};
|
||||
}
|
||||
if (!settings_doc.isObject ())
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: top level must be a JSON object")};
|
||||
}
|
||||
auto const& settings = settings_doc.object ();
|
||||
QFile settings_file {settings_file_name};
|
||||
if (settings_file.open (QFile::ReadOnly))
|
||||
{
|
||||
QJsonParseError status;
|
||||
auto settings_doc = QJsonDocument::fromJson (settings_file.readAll (), &status);
|
||||
if (status.error)
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: %1 at character offset %2")
|
||||
.arg (status.errorString ()).arg (status.offset)};
|
||||
}
|
||||
if (!settings_doc.isObject ())
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: top level must be a JSON object")};
|
||||
}
|
||||
auto const& settings = settings_doc.object ();
|
||||
|
||||
//
|
||||
// configuration settings
|
||||
//
|
||||
auto const& config = settings["config"];
|
||||
if (!config.isUndefined ())
|
||||
{
|
||||
if (!config.isObject ())
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: config must be a JSON object")};
|
||||
}
|
||||
auto const& config_list = config.toObject ();
|
||||
for (auto item = config_list.constBegin (); item != config_list.constEnd (); ++item)
|
||||
{
|
||||
set_conf (item.key ().toLocal8Bit ().constData ()
|
||||
, (*item).toVariant ().toString ().toLocal8Bit ().constData ());
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// configuration settings
|
||||
//
|
||||
auto const& config = settings["config"];
|
||||
if (!config.isUndefined ())
|
||||
{
|
||||
if (!config.isObject ())
|
||||
{
|
||||
throw error {tr ("Hamlib settings file error: config must be a JSON object")};
|
||||
}
|
||||
auto const& config_list = config.toObject ();
|
||||
for (auto item = config_list.constBegin (); item != config_list.constEnd (); ++item)
|
||||
{
|
||||
set_conf (item.key ().toLocal8Bit ().constData ()
|
||||
, (*item).toVariant ().toString ().toLocal8Bit ().constData ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (RIG_MODEL_DUMMY != model_number)
|
||||
if (!is_dummy_)
|
||||
{
|
||||
switch (rig_->caps->port_type)
|
||||
{
|
||||
@ -354,8 +360,7 @@ HamlibTransceiver::HamlibTransceiver (int model_number, TransceiverFactory::Para
|
||||
case TransceiverFactory::PTT_method_RTS:
|
||||
if (!params.ptt_port.isEmpty ()
|
||||
&& params.ptt_port != "None"
|
||||
&& (RIG_MODEL_DUMMY == model_number
|
||||
|| params.ptt_port != params.serial_port))
|
||||
&& (is_dummy_ || params.ptt_port != params.serial_port))
|
||||
{
|
||||
#if defined (WIN32)
|
||||
set_conf ("ptt_pathname", ("\\\\.\\" + params.ptt_port).toLatin1 ().data ());
|
||||
@ -381,22 +386,20 @@ HamlibTransceiver::HamlibTransceiver (int model_number, TransceiverFactory::Para
|
||||
// rig_set_freq_callback (rig_.data (), &frequency_change_callback, this);
|
||||
}
|
||||
|
||||
HamlibTransceiver::~HamlibTransceiver ()
|
||||
{
|
||||
}
|
||||
|
||||
void HamlibTransceiver::error_check (int ret_code, QString const& doing) const
|
||||
{
|
||||
if (RIG_OK != ret_code)
|
||||
{
|
||||
TRACE_CAT_POLL ("error:" << rigerror (ret_code));
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "error:" << rigerror (ret_code));
|
||||
throw error {tr ("Hamlib error: %1 while %2").arg (rigerror (ret_code)).arg (doing)};
|
||||
}
|
||||
}
|
||||
|
||||
void HamlibTransceiver::do_start ()
|
||||
int HamlibTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT (QString::fromLatin1 (rig_->caps->mfg_name).trimmed () << QString::fromLatin1 (rig_->caps->model_name).trimmed ());
|
||||
TRACE_CAT ("HamlibTransceiver",
|
||||
QString::fromLatin1 (rig_->caps->mfg_name).trimmed ()
|
||||
<< QString::fromLatin1 (rig_->caps->model_name).trimmed ());
|
||||
|
||||
error_check (rig_open (rig_.data ()), tr ("opening connection to rig"));
|
||||
|
||||
@ -407,6 +410,12 @@ void HamlibTransceiver::do_start ()
|
||||
if (-RIG_ENAVAIL == rc || -RIG_ENIMPL == rc)
|
||||
{
|
||||
get_vfo_works_ = false;
|
||||
// determine if the rig uses single VFO addressing i.e. A/B and
|
||||
// no get_vfo function
|
||||
if (rig_->state.vfo_list & RIG_VFO_B)
|
||||
{
|
||||
one_VFO_ = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -430,38 +439,38 @@ void HamlibTransceiver::do_start ()
|
||||
// assume it is as when we started by setting at open time right
|
||||
// here. We also gather/set other initial state.
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f1), tr ("getting current frequency"));
|
||||
TRACE_CAT ("current frequency =" << f1);
|
||||
TRACE_CAT ("HamlibTransceiver", "current frequency =" << f1);
|
||||
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w), tr ("getting current mode"));
|
||||
TRACE_CAT ("current mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
TRACE_CAT ("HamlibTransceiver", "current mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
|
||||
if (!rig_->caps->set_vfo)
|
||||
{
|
||||
TRACE_CAT ("rig_vfo_op TOGGLE");
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_vfo_op TOGGLE");
|
||||
error_check (rig_vfo_op (rig_.data (), RIG_VFO_CURR, RIG_OP_TOGGLE), tr ("exchanging VFOs"));
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("rig_set_vfo to other VFO");
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_vfo to other VFO");
|
||||
error_check (rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_B ? RIG_VFO_B : RIG_VFO_SUB), tr ("setting current VFO"));
|
||||
}
|
||||
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f2), tr ("getting other VFO frequency"));
|
||||
TRACE_CAT ("rig_get_freq other frequency =" << f2);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_freq other frequency =" << f2);
|
||||
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &mb, &wb), tr ("getting other VFO mode"));
|
||||
TRACE_CAT ("rig_get_mode other mode =" << rig_strrmode (mb) << "bw =" << wb);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode other mode =" << rig_strrmode (mb) << "bw =" << wb);
|
||||
|
||||
update_other_frequency (f2);
|
||||
|
||||
if (!rig_->caps->set_vfo)
|
||||
{
|
||||
TRACE_CAT ("rig_vfo_op TOGGLE");
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_vfo_op TOGGLE");
|
||||
error_check (rig_vfo_op (rig_.data (), RIG_VFO_CURR, RIG_OP_TOGGLE), tr ("exchanging VFOs"));
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("rig_set_vfo A/MAIN");
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_vfo A/MAIN");
|
||||
error_check (rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN), tr ("setting current VFO"));
|
||||
}
|
||||
|
||||
@ -472,15 +481,15 @@ void HamlibTransceiver::do_start ()
|
||||
else
|
||||
{
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f1), tr ("getting frequency"));
|
||||
TRACE_CAT ("rig_get_freq frequency =" << f1);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_freq frequency =" << f1);
|
||||
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w), tr ("getting mode"));
|
||||
TRACE_CAT ("rig_get_mode mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
|
||||
update_rx_frequency (f1);
|
||||
}
|
||||
|
||||
// TRACE_CAT ("rig_set_split_vfo split off");
|
||||
// TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split off");
|
||||
// error_check (rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, RIG_SPLIT_OFF, RIG_VFO_CURR), tr ("setting split off"));
|
||||
// update_split (false);
|
||||
}
|
||||
@ -491,7 +500,7 @@ void HamlibTransceiver::do_start ()
|
||||
if (get_vfo_works_ && rig_->caps->get_vfo)
|
||||
{
|
||||
error_check (rig_get_vfo (rig_.data (), &v), tr ("getting current VFO")); // has side effect of establishing current VFO inside hamlib
|
||||
TRACE_CAT ("rig_get_vfo current VFO = " << rig_strvfo (v));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_vfo current VFO = " << rig_strvfo (v));
|
||||
}
|
||||
|
||||
reversed_ = RIG_VFO_B == v;
|
||||
@ -500,7 +509,7 @@ void HamlibTransceiver::do_start ()
|
||||
{
|
||||
if (RIG_OK == rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w))
|
||||
{
|
||||
TRACE_CAT ("rig_get_mode current mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode current mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -508,7 +517,7 @@ void HamlibTransceiver::do_start ()
|
||||
// Some rigs (HDSDR) don't have a working way of
|
||||
// reporting MODE so we give up on mode queries -
|
||||
// sets will still cause an error
|
||||
TRACE_CAT_POLL ("rig_get_mode can't do on this rig");
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_mode can't do on this rig");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -530,9 +539,30 @@ void HamlibTransceiver::do_start ()
|
||||
}
|
||||
}
|
||||
|
||||
int resolution {0};
|
||||
freq_t current_frequency;
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, ¤t_frequency), tr ("getting current VFO frequency"));
|
||||
Frequency f = current_frequency;
|
||||
if (f && !(f % 10))
|
||||
{
|
||||
auto test_frequency = f - f % 100 + 55;
|
||||
error_check (rig_set_freq (rig_.data (), RIG_VFO_CURR, test_frequency), tr ("setting frequency"));
|
||||
freq_t new_frequency;
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &new_frequency), tr ("getting current VFO frequency"));
|
||||
switch (static_cast<Radio::FrequencyDelta> (new_frequency - test_frequency))
|
||||
{
|
||||
case -5: resolution = -1; break; // 10Hz truncated
|
||||
case 5: resolution = 1; break; // 10Hz rounded
|
||||
case -55: resolution = -2; break; // 100Hz truncated
|
||||
case 45: resolution = 2; break; // 100Hz rounded
|
||||
}
|
||||
error_check (rig_set_freq (rig_.data (), RIG_VFO_CURR, current_frequency), tr ("setting frequency"));
|
||||
}
|
||||
|
||||
poll ();
|
||||
|
||||
TRACE_CAT ("exit" << state () << "reversed =" << reversed_);
|
||||
TRACE_CAT ("HamlibTransceiver", "exit" << state () << "reversed =" << reversed_ << "resolution = " << resolution);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
void HamlibTransceiver::do_stop ()
|
||||
@ -551,77 +581,92 @@ void HamlibTransceiver::do_stop ()
|
||||
rig_close (rig_.data ());
|
||||
}
|
||||
|
||||
TRACE_CAT ("state:" << state () << "reversed =" << reversed_);
|
||||
TRACE_CAT ("HamlibTransceiver", "state:" << state () << "reversed =" << reversed_);
|
||||
}
|
||||
|
||||
auto HamlibTransceiver::get_vfos () const -> std::tuple<vfo_t, vfo_t>
|
||||
auto HamlibTransceiver::get_vfos (bool for_split) const -> std::tuple<vfo_t, vfo_t>
|
||||
{
|
||||
if (get_vfo_works_ && rig_->caps->get_vfo)
|
||||
{
|
||||
vfo_t v;
|
||||
error_check (rig_get_vfo (rig_.data (), &v), tr ("getting current VFO")); // has side effect of establishing current VFO inside hamlib
|
||||
TRACE_CAT ("rig_get_vfo VFO = " << rig_strvfo (v));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_vfo VFO = " << rig_strvfo (v));
|
||||
|
||||
reversed_ = RIG_VFO_B == v;
|
||||
}
|
||||
else if (rig_->caps->set_vfo && rig_->caps->set_split_vfo)
|
||||
else if (!for_split && rig_->caps->set_vfo && rig_->caps->set_split_vfo)
|
||||
{
|
||||
// use VFO A/MAIN for main frequency and B/SUB for Tx
|
||||
// frequency if split since these type of radios can only
|
||||
// support this way around
|
||||
|
||||
TRACE_CAT ("rig_set_vfo VFO = A/MAIN");
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_vfo VFO = A/MAIN");
|
||||
error_check (rig_set_vfo (rig_.data (), rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN), tr ("setting current VFO"));
|
||||
}
|
||||
// else only toggle available but both VFOs should be substitutable
|
||||
|
||||
auto rx_vfo = rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN;
|
||||
auto tx_vfo = (WSJT_RIG_NONE_CAN_SPLIT || !is_dummy_)
|
||||
auto tx_vfo = (WSJT_RIG_NONE_CAN_SPLIT || !is_dummy_) && for_split
|
||||
? (rig_->state.vfo_list & RIG_VFO_B ? RIG_VFO_B : RIG_VFO_SUB)
|
||||
: rx_vfo;
|
||||
if (reversed_)
|
||||
{
|
||||
TRACE_CAT ("reversing VFOs");
|
||||
TRACE_CAT ("HamlibTransceiver", "reversing VFOs");
|
||||
std::swap (rx_vfo, tx_vfo);
|
||||
}
|
||||
|
||||
TRACE_CAT ("RX VFO = " << rig_strvfo (rx_vfo) << " TX VFO = " << rig_strvfo (tx_vfo));
|
||||
TRACE_CAT ("HamlibTransceiver", "RX VFO = " << rig_strvfo (rx_vfo) << " TX VFO = " << rig_strvfo (tx_vfo));
|
||||
return std::make_tuple (rx_vfo, tx_vfo);
|
||||
}
|
||||
|
||||
void HamlibTransceiver::do_frequency (Frequency f, MODE m)
|
||||
void HamlibTransceiver::do_frequency (Frequency f, MODE m, bool no_ignore)
|
||||
{
|
||||
TRACE_CAT (f << "mode:" << m << "reversed:" << reversed_);
|
||||
TRACE_CAT ("HamlibTransceiver", f << "mode:" << m << "reversed:" << reversed_);
|
||||
|
||||
// for the 1st time as a band change may cause a recalled mode to be
|
||||
// set
|
||||
error_check (rig_set_freq (rig_.data (), RIG_VFO_CURR, f), tr ("setting frequency"));
|
||||
|
||||
if (mode_query_works_ && UNK != m)
|
||||
// only change when receiving or simplex or direct VFO addressing
|
||||
// unavailable or forced
|
||||
if (!state ().ptt () || !state ().split () || !one_VFO_ || no_ignore)
|
||||
{
|
||||
do_mode (m, false);
|
||||
|
||||
// for the 2nd time because a mode change may have caused a
|
||||
// frequency change
|
||||
// for the 1st time as a band change may cause a recalled mode to be
|
||||
// set
|
||||
error_check (rig_set_freq (rig_.data (), RIG_VFO_CURR, f), tr ("setting frequency"));
|
||||
update_rx_frequency (f);
|
||||
|
||||
// for the second time because some rigs change mode according
|
||||
// to frequency such as the TS-2000 auto mode setting
|
||||
do_mode (m, false);
|
||||
if (mode_query_works_ && UNK != m)
|
||||
{
|
||||
rmode_t current_mode;
|
||||
pbwidth_t current_width;
|
||||
auto new_mode = map_mode (m);
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NORMAL), tr ("setting current VFO mode"));
|
||||
|
||||
// for the 2nd time because a mode change may have caused a
|
||||
// frequency change
|
||||
error_check (rig_set_freq (rig_.data (), RIG_VFO_CURR, f), tr ("setting frequency"));
|
||||
|
||||
// for the second time because some rigs change mode according
|
||||
// to frequency such as the TS-2000 auto mode setting
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NORMAL), tr ("setting current VFO mode"));
|
||||
}
|
||||
update_mode (m);
|
||||
}
|
||||
}
|
||||
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
|
||||
void HamlibTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode)
|
||||
void HamlibTransceiver::do_tx_frequency (Frequency tx, bool no_ignore)
|
||||
{
|
||||
TRACE_CAT (tx << "rationalise mode:" << rationalise_mode << "reversed:" << reversed_);
|
||||
TRACE_CAT ("HamlibTransceiver", tx << "reversed:" << reversed_);
|
||||
|
||||
if (WSJT_RIG_NONE_CAN_SPLIT || !is_dummy_) // split is meaningless if you can't see it
|
||||
{
|
||||
auto split = tx ? RIG_SPLIT_ON : RIG_SPLIT_OFF;
|
||||
update_split (tx);
|
||||
auto vfos = get_vfos ();
|
||||
auto vfos = get_vfos (tx);
|
||||
// auto rx_vfo = std::get<0> (vfos); // or use RIG_VFO_CURR
|
||||
auto tx_vfo = std::get<1> (vfos);
|
||||
|
||||
@ -640,7 +685,7 @@ void HamlibTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode)
|
||||
// much we can do since the Hamlib Library needs this
|
||||
// call at least once to establish the Tx VFO. Best we
|
||||
// can do is only do this once per session.
|
||||
TRACE_CAT ("rig_set_split_vfo split =" << split);
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split =" << split);
|
||||
auto rc = rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo);
|
||||
if (tx || (-RIG_ENAVAIL != rc && -RIG_ENIMPL != rc))
|
||||
{
|
||||
@ -652,85 +697,126 @@ void HamlibTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode)
|
||||
// specific rig.
|
||||
error_check (rc, tr ("setting/unsetting split mode"));
|
||||
}
|
||||
|
||||
tickle_hamlib_ = false;
|
||||
update_split (tx);
|
||||
}
|
||||
|
||||
hamlib_tx_vfo_fixup fixup (rig_.data (), tx_vfo);
|
||||
// do this before setting the mode because changing band may
|
||||
// recall the last mode used on the target band
|
||||
error_check (rig_set_split_freq (rig_.data (), RIG_VFO_CURR, tx), tr ("setting split TX frequency"));
|
||||
|
||||
if (rationalise_mode)
|
||||
// just change current when transmitting with single VFO
|
||||
// addressing
|
||||
if (state ().ptt () && one_VFO_)
|
||||
{
|
||||
rmode_t current_mode;
|
||||
pbwidth_t current_width;
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split =" << split);
|
||||
error_check (rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo), tr ("setting split mode"));
|
||||
|
||||
error_check (rig_get_split_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting mode of split TX VFO"));
|
||||
TRACE_CAT ("rig_get_split_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
error_check (rig_set_freq (rig_.data (), RIG_VFO_CURR, tx), tr ("setting frequency"));
|
||||
|
||||
auto new_mode = map_mode (state ().mode ());
|
||||
if (new_mode != current_mode)
|
||||
if (set_rig_mode_ && mode_query_works_)
|
||||
{
|
||||
TRACE_CAT ("rig_set_split_mode mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_split_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NORMAL), tr ("setting split TX VFO mode"));
|
||||
rmode_t current_mode;
|
||||
pbwidth_t current_width;
|
||||
auto new_mode = map_mode (state ().mode ());
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
|
||||
// do this again as setting the mode may change the frequency
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NORMAL), tr ("setting current VFO mode"));
|
||||
}
|
||||
}
|
||||
update_other_frequency (tx);
|
||||
}
|
||||
else if (!one_VFO_ || no_ignore) // if not single VFO addressing and not forced
|
||||
{
|
||||
hamlib_tx_vfo_fixup fixup (rig_.data (), tx_vfo);
|
||||
if (set_rig_mode_)
|
||||
{
|
||||
auto new_mode = map_mode (state ().mode ());
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_freq_mode freq = " << tx
|
||||
<< " mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_split_freq_mode (rig_.data (), RIG_VFO_CURR, tx, new_mode, RIG_PASSBAND_NORMAL), tr ("setting split TX frequency and mode"));
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_freq freq = " << tx);
|
||||
error_check (rig_set_split_freq (rig_.data (), RIG_VFO_CURR, tx), tr ("setting split TX frequency"));
|
||||
}
|
||||
// Enable split last since some rigs (Kenwood for one) come out
|
||||
// of split when you switch RX VFO (to set split mode above for
|
||||
// example). Also the Elecraft K3 will refuse to go to split
|
||||
// with certain VFO A/B mode combinations.
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split =" << split);
|
||||
error_check (rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo), tr ("setting split mode"));
|
||||
update_other_frequency (tx);
|
||||
update_split (tx);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable split last since some rigs (Kenwood for one) come out
|
||||
// of split when you switch RX VFO (to set split mode above for
|
||||
// example). Also the Elecraft K3 will refuse to go to split
|
||||
// with certain VFO A/B mode combinations.
|
||||
TRACE_CAT ("rig_set_split_vfo split =" << split);
|
||||
auto rc = rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo);
|
||||
if (tx || (-RIG_ENAVAIL != rc && -RIG_ENIMPL != rc))
|
||||
else
|
||||
{
|
||||
// On rigs that can't have split controlled only throw an
|
||||
// exception when an error other than command not accepted
|
||||
// is returned when trying to leave split mode. This allows
|
||||
// fake split mode and non-split mode to work without error
|
||||
// on such rigs without having to know anything about the
|
||||
// specific rig.
|
||||
error_check (rc, tr ("setting/unsetting split mode"));
|
||||
// Disable split
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_vfo split =" << split);
|
||||
auto rc = rig_set_split_vfo (rig_.data (), RIG_VFO_CURR, split, tx_vfo);
|
||||
if (tx || (-RIG_ENAVAIL != rc && -RIG_ENIMPL != rc))
|
||||
{
|
||||
// On rigs that can't have split controlled only throw an
|
||||
// exception when an error other than command not accepted
|
||||
// is returned when trying to leave split mode. This allows
|
||||
// fake split mode and non-split mode to work without error
|
||||
// on such rigs without having to know anything about the
|
||||
// specific rig.
|
||||
error_check (rc, tr ("setting/unsetting split mode"));
|
||||
}
|
||||
update_other_frequency (tx);
|
||||
update_split (tx);
|
||||
}
|
||||
|
||||
update_other_frequency (tx);
|
||||
}
|
||||
}
|
||||
|
||||
void HamlibTransceiver::do_mode (MODE mode, bool rationalise)
|
||||
void HamlibTransceiver::do_mode (MODE mode)
|
||||
{
|
||||
TRACE_CAT (mode << "rationalise:" << rationalise);
|
||||
TRACE_CAT ("HamlibTransceiver", mode);
|
||||
|
||||
auto vfos = get_vfos ();
|
||||
auto vfos = get_vfos (state ().split ());
|
||||
// auto rx_vfo = std::get<0> (vfos);
|
||||
auto tx_vfo = std::get<1> (vfos);
|
||||
|
||||
rmode_t current_mode;
|
||||
pbwidth_t current_width;
|
||||
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
|
||||
auto new_mode = map_mode (mode);
|
||||
if (new_mode != current_mode)
|
||||
|
||||
// only change when receiving or simplex if direct VFO addressing unavailable
|
||||
if (!(state ().ptt () && state ().split () && one_VFO_))
|
||||
{
|
||||
TRACE_CAT ("rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NORMAL), tr ("setting current VFO mode"));
|
||||
}
|
||||
|
||||
if (!is_dummy_ && state ().split () && rationalise)
|
||||
{
|
||||
error_check (rig_get_split_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting split TX VFO mode"));
|
||||
TRACE_CAT ("rig_get_split_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("rig_set_split_mode mode = " << rig_strrmode (new_mode));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NORMAL), tr ("setting current VFO mode"));
|
||||
}
|
||||
}
|
||||
|
||||
// just change current when transmitting split with one VFO mode
|
||||
if (state ().ptt () && state ().split () && one_VFO_)
|
||||
{
|
||||
error_check (rig_get_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting current VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_mode mode = " << rig_strrmode (new_mode));
|
||||
error_check (rig_set_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NORMAL), tr ("setting current VFO mode"));
|
||||
}
|
||||
}
|
||||
else if (state ().split () && !one_VFO_)
|
||||
{
|
||||
error_check (rig_get_split_mode (rig_.data (), RIG_VFO_CURR, ¤t_mode, ¤t_width), tr ("getting split TX VFO mode"));
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_get_split_mode mode = " << rig_strrmode (current_mode) << "bw =" << current_width);
|
||||
|
||||
if (new_mode != current_mode)
|
||||
{
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_split_mode mode = " << rig_strrmode (new_mode));
|
||||
hamlib_tx_vfo_fixup fixup (rig_.data (), tx_vfo);
|
||||
error_check (rig_set_split_mode (rig_.data (), RIG_VFO_CURR, new_mode, RIG_PASSBAND_NORMAL), tr ("setting split TX VFO mode"));
|
||||
}
|
||||
@ -757,17 +843,22 @@ void HamlibTransceiver::poll ()
|
||||
{
|
||||
vfo_t v;
|
||||
error_check (rig_get_vfo (rig_.data (), &v), tr ("getting current VFO")); // has side effect of establishing current VFO inside hamlib
|
||||
TRACE_CAT_POLL ("VFO =" << rig_strvfo (v));
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "VFO =" << rig_strvfo (v));
|
||||
reversed_ = RIG_VFO_B == v;
|
||||
}
|
||||
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f), tr ("getting current VFO frequency"));
|
||||
TRACE_CAT_POLL ("rig_get_freq frequency =" << f);
|
||||
update_rx_frequency (f);
|
||||
// only read when receiving or simplex
|
||||
if (!state ().ptt () || !state ().split ())
|
||||
{
|
||||
error_check (rig_get_freq (rig_.data (), RIG_VFO_CURR, &f), tr ("getting current VFO frequency"));
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_freq frequency =" << f);
|
||||
update_rx_frequency (f);
|
||||
}
|
||||
|
||||
if ((WSJT_RIG_NONE_CAN_SPLIT || !is_dummy_)
|
||||
&& state ().split ()
|
||||
&& (rig_->caps->targetable_vfo & (RIG_TARGETABLE_FREQ | RIG_TARGETABLE_PURE)))
|
||||
&& (rig_->caps->targetable_vfo & (RIG_TARGETABLE_FREQ | RIG_TARGETABLE_PURE))
|
||||
&& !one_VFO_)
|
||||
{
|
||||
// only read "other" VFO if in split, this allows rigs like
|
||||
// FlexRadio to work in Kenwood TS-2000 mode despite them
|
||||
@ -779,12 +870,14 @@ void HamlibTransceiver::poll ()
|
||||
, reversed_
|
||||
? (rig_->state.vfo_list & RIG_VFO_A ? RIG_VFO_A : RIG_VFO_MAIN)
|
||||
: (rig_->state.vfo_list & RIG_VFO_B ? RIG_VFO_B : RIG_VFO_SUB)
|
||||
, &f), tr ("getting current VFO frequency"));
|
||||
TRACE_CAT_POLL ("rig_get_freq other VFO =" << f);
|
||||
, &f), tr ("getting other VFO frequency"));
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_freq other VFO =" << f);
|
||||
update_other_frequency (f);
|
||||
}
|
||||
|
||||
if (mode_query_works_)
|
||||
// only read when receiving or simplex if direct VFO addressing unavailable
|
||||
if ((!state ().ptt () || !state ().split ())
|
||||
&& mode_query_works_)
|
||||
{
|
||||
// We have to ignore errors here because Yaesu FTdx... rigs can
|
||||
// report the wrong mode when transmitting split with different
|
||||
@ -795,12 +888,12 @@ void HamlibTransceiver::poll ()
|
||||
auto rc = rig_get_mode (rig_.data (), RIG_VFO_CURR, &m, &w);
|
||||
if (RIG_OK == rc)
|
||||
{
|
||||
TRACE_CAT_POLL ("rig_get_mode mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_mode mode =" << rig_strrmode (m) << "bw =" << w);
|
||||
update_mode (map_mode (m));
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT_POLL ("rig_get_mode mode failed with rc:" << rc << "ignoring");
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_mode mode failed with rc:" << rc << "ignoring");
|
||||
}
|
||||
}
|
||||
|
||||
@ -811,7 +904,7 @@ void HamlibTransceiver::poll ()
|
||||
auto rc = rig_get_split_vfo (rig_.data (), RIG_VFO_CURR, &s, &v);
|
||||
if (-RIG_OK == rc && RIG_SPLIT_ON == s)
|
||||
{
|
||||
TRACE_CAT_POLL ("rig_get_split_vfo split = " << s << " VFO = " << rig_strvfo (v));
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_split_vfo split = " << s << " VFO = " << rig_strvfo (v));
|
||||
update_split (true);
|
||||
// if (RIG_VFO_A == v)
|
||||
// {
|
||||
@ -820,14 +913,14 @@ void HamlibTransceiver::poll ()
|
||||
}
|
||||
else if (-RIG_OK == rc) // not split
|
||||
{
|
||||
TRACE_CAT_POLL ("rig_get_split_vfo split = " << s << " VFO = " << rig_strvfo (v));
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_split_vfo split = " << s << " VFO = " << rig_strvfo (v));
|
||||
update_split (false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Some rigs (Icom) don't have a way of reporting SPLIT
|
||||
// mode
|
||||
TRACE_CAT_POLL ("rig_get_split_vfo can't do on this rig");
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_split_vfo can't do on this rig");
|
||||
// just report how we see it based on prior commands
|
||||
split_query_works_ = false;
|
||||
}
|
||||
@ -842,7 +935,7 @@ void HamlibTransceiver::poll ()
|
||||
// support command
|
||||
{
|
||||
error_check (rc, tr ("getting PTT state"));
|
||||
TRACE_CAT_POLL ("rig_get_ptt PTT =" << p);
|
||||
TRACE_CAT_POLL ("HamlibTransceiver", "rig_get_ptt PTT =" << p);
|
||||
update_PTT (!(RIG_PTT_OFF == p));
|
||||
}
|
||||
}
|
||||
@ -864,12 +957,12 @@ void HamlibTransceiver::poll ()
|
||||
|
||||
void HamlibTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT (on << state () << "reversed =" << reversed_);
|
||||
TRACE_CAT ("HamlibTransceiver", on << state () << "reversed =" << reversed_);
|
||||
if (on)
|
||||
{
|
||||
if (RIG_PTT_NONE != rig_->state.pttport.type.ptt)
|
||||
{
|
||||
TRACE_CAT ("rig_set_ptt PTT = true");
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_ptt PTT = true");
|
||||
error_check (rig_set_ptt (rig_.data (), RIG_VFO_CURR
|
||||
, RIG_PTT_RIG_MICDATA == rig_->caps->ptt_type && back_ptt_port_
|
||||
? RIG_PTT_ON_DATA : RIG_PTT_ON), tr ("setting PTT on"));
|
||||
@ -879,7 +972,7 @@ void HamlibTransceiver::do_ptt (bool on)
|
||||
{
|
||||
if (RIG_PTT_NONE != rig_->state.pttport.type.ptt)
|
||||
{
|
||||
TRACE_CAT ("rig_set_ptt PTT = false");
|
||||
TRACE_CAT ("HamlibTransceiver", "rig_set_ptt PTT = false");
|
||||
error_check (rig_set_ptt (rig_.data (), RIG_VFO_CURR, RIG_PTT_OFF), tr ("setting PTT off"));
|
||||
}
|
||||
}
|
||||
|
@ -26,16 +26,17 @@ class HamlibTransceiver final
|
||||
public:
|
||||
static void register_transceivers (TransceiverFactory::Transceivers *);
|
||||
|
||||
explicit HamlibTransceiver (int model_number, TransceiverFactory::ParameterPack const&);
|
||||
explicit HamlibTransceiver (TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port);
|
||||
~HamlibTransceiver ();
|
||||
explicit HamlibTransceiver (int model_number, TransceiverFactory::ParameterPack const&,
|
||||
QObject * parent = nullptr);
|
||||
explicit HamlibTransceiver (TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port,
|
||||
QObject * parent = nullptr);
|
||||
|
||||
private:
|
||||
void do_start () override;
|
||||
int do_start () override;
|
||||
void do_stop () override;
|
||||
void do_frequency (Frequency, MODE) override;
|
||||
void do_tx_frequency (Frequency, bool rationalise_mode) override;
|
||||
void do_mode (MODE, bool rationalise) override;
|
||||
void do_frequency (Frequency, MODE, bool no_ignore) override;
|
||||
void do_tx_frequency (Frequency, bool no_ignore) override;
|
||||
void do_mode (MODE) override;
|
||||
void do_ptt (bool) override;
|
||||
|
||||
void poll () override;
|
||||
@ -45,12 +46,14 @@ class HamlibTransceiver final
|
||||
QByteArray get_conf (char const * item);
|
||||
Transceiver::MODE map_mode (rmode_t) const;
|
||||
rmode_t map_mode (Transceiver::MODE mode) const;
|
||||
std::tuple<vfo_t, vfo_t> get_vfos () const;
|
||||
std::tuple<vfo_t, vfo_t> get_vfos (bool for_split) const;
|
||||
|
||||
struct RIGDeleter {static void cleanup (RIG *);};
|
||||
QScopedPointer<RIG, RIGDeleter> rig_;
|
||||
|
||||
bool set_rig_mode_;
|
||||
bool back_ptt_port_;
|
||||
bool one_VFO_;
|
||||
bool is_dummy_;
|
||||
|
||||
// these are saved on destruction so we can start new instances
|
||||
|
@ -13,20 +13,25 @@
|
||||
LiveFrequencyValidator::LiveFrequencyValidator (QComboBox * combo_box
|
||||
, Bands const * bands
|
||||
, FrequencyList const * frequencies
|
||||
, Frequency const * nominal_frequency
|
||||
, QWidget * parent)
|
||||
: QRegExpValidator {
|
||||
QRegExp { // frequency in MHz or band
|
||||
bands->data (QModelIndex {}).toString () // out of band string
|
||||
+ QString {R"(|((\d{0,6}(\)"} // or up to 6 digits
|
||||
+ QLocale {}.decimalPoint () // (followed by decimal separator
|
||||
+ R"(\d{0,2})?)([Mm]{1,2}|([Cc][Mm])))|(\d{0,4}(\)" // followed by up to 2 digits and either 'm' or 'cm' or 'mm' (case insensitive))
|
||||
+ R"(\d{0,2})?)([Mm]{1,2}|([Cc][Mm])))|(\d{0,6}(\)" // followed by up to 2 digits and either 'm' or 'cm' or 'mm' (case insensitive))
|
||||
+ QLocale {}.decimalPoint () // or a decimal separator
|
||||
+ R"(\d{0,6})?))" // followed by up to 6 digits
|
||||
+ R"(\d{0,6})?)|(\d{0,3}(\)" // followed by up to 6
|
||||
// digits or a decimal number
|
||||
+ QLocale {}.decimalPoint () // or a decimal separator
|
||||
+ R"(\d{0,6})?[Kk]))" // followed by a 'k' or 'K'
|
||||
}
|
||||
, parent
|
||||
}
|
||||
, bands_ {bands}
|
||||
, frequencies_ {frequencies}
|
||||
, nominal_frequency_ {nominal_frequency}
|
||||
, combo_box_ {combo_box}
|
||||
{
|
||||
}
|
||||
@ -65,6 +70,14 @@ void LiveFrequencyValidator::fixup (QString& input) const
|
||||
input = QString {};
|
||||
}
|
||||
}
|
||||
else if (input.contains (QChar {'k'}, Qt::CaseInsensitive))
|
||||
{
|
||||
// kHz in current MHz input
|
||||
auto f = Radio::frequency (input.remove (QChar {'k'}, Qt::CaseInsensitive), 3);
|
||||
f += *nominal_frequency_ / 1000000u * 1000000u;
|
||||
input = bands_->find (f);
|
||||
Q_EMIT valid (f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// frequency input
|
||||
|
@ -1,52 +1,56 @@
|
||||
#ifndef LIVE_FREQUENCY_VALIDATOR_HPP__
|
||||
#define LIVE_FREQUENCY_VALIDATOR_HPP__
|
||||
|
||||
#include <QObject>
|
||||
#include <QRegExpValidator>
|
||||
|
||||
#include "Radio.hpp"
|
||||
|
||||
class Bands;
|
||||
class FrequencyList;
|
||||
class QComboBox;
|
||||
class QWidget;
|
||||
|
||||
//
|
||||
// Class LiveFrequencyValidator
|
||||
//
|
||||
// QLineEdit validator that controls input to an editable
|
||||
// QComboBox where the user can enter a valid band or a valid
|
||||
// frequency in megahetz.
|
||||
//
|
||||
// Collabrations
|
||||
//
|
||||
// Implements the QRegExpValidator interface. Validates input
|
||||
// from the supplied QComboBox as either a valid frequency in
|
||||
// megahertz or a valid band as defined by the supplied column of
|
||||
// the supplied QAbstractItemModel.
|
||||
//
|
||||
class LiveFrequencyValidator final
|
||||
: public QRegExpValidator
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
using Frequency = Radio::Frequency;
|
||||
|
||||
LiveFrequencyValidator (QComboBox * combo_box // associated combo box
|
||||
, Bands const * bands // bands model
|
||||
, FrequencyList const * frequencies // working frequencies model
|
||||
, QWidget * parent = nullptr);
|
||||
|
||||
State validate (QString& input, int& pos) const override;
|
||||
void fixup (QString& input) const override;
|
||||
|
||||
Q_SIGNAL void valid (Frequency) const;
|
||||
|
||||
private:
|
||||
Bands const * bands_;
|
||||
FrequencyList const * frequencies_;
|
||||
QComboBox * combo_box_;
|
||||
};
|
||||
|
||||
#endif
|
||||
#ifndef LIVE_FREQUENCY_VALIDATOR_HPP__
|
||||
#define LIVE_FREQUENCY_VALIDATOR_HPP__
|
||||
|
||||
#include <QObject>
|
||||
#include <QRegExpValidator>
|
||||
|
||||
#include "Radio.hpp"
|
||||
|
||||
class Bands;
|
||||
class FrequencyList;
|
||||
class QComboBox;
|
||||
class QWidget;
|
||||
|
||||
//
|
||||
// Class LiveFrequencyValidator
|
||||
//
|
||||
// QLineEdit validator that controls input to an editable
|
||||
// QComboBox where the user can enter a valid band or a valid
|
||||
// frequency in megahetz.
|
||||
//
|
||||
// Collabrations
|
||||
//
|
||||
// Implements the QRegExpValidator interface. Validates input
|
||||
// from the supplied QComboBox as either a valid frequency in
|
||||
// megahertz or a valid band as defined by the supplied column of
|
||||
// the supplied QAbstractItemModel.
|
||||
//
|
||||
class LiveFrequencyValidator final
|
||||
: public QRegExpValidator
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
using Frequency = Radio::Frequency;
|
||||
|
||||
LiveFrequencyValidator (QComboBox * combo_box // associated combo box
|
||||
, Bands const * bands // bands model
|
||||
, FrequencyList const * frequencies // working
|
||||
// frequencies
|
||||
// model
|
||||
, Frequency const * nominal_frequency
|
||||
, QWidget * parent = nullptr);
|
||||
|
||||
State validate (QString& input, int& pos) const override;
|
||||
void fixup (QString& input) const override;
|
||||
|
||||
Q_SIGNAL void valid (Frequency) const;
|
||||
|
||||
private:
|
||||
Bands const * bands_;
|
||||
FrequencyList const * frequencies_;
|
||||
Frequency const * nominal_frequency_;
|
||||
QComboBox * combo_box_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <objbase.h>
|
||||
#include <QThread>
|
||||
|
||||
#include "qt_helpers.hpP"
|
||||
|
||||
@ -48,7 +49,7 @@ auto OmniRigTransceiver::map_mode (OmniRig::RigParamX param) -> MODE
|
||||
{
|
||||
return FM;
|
||||
}
|
||||
TRACE_CAT ("unrecognized mode");
|
||||
TRACE_CAT ("OmniRigTransceiver", "unrecognized mode");
|
||||
throw_qstring (tr ("OmniRig: unrecognized mode"));
|
||||
return UNK;
|
||||
}
|
||||
@ -70,7 +71,7 @@ OmniRig::RigParamX OmniRigTransceiver::map_mode (MODE mode)
|
||||
case DIG_FM: return OmniRig::PM_FM;
|
||||
default: break;
|
||||
}
|
||||
return OmniRig::PM_SSB_U; // quieten compiler grumble
|
||||
return OmniRig::PM_SSB_U; // quieten compiler grumble
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::register_transceivers (TransceiverFactory::Transceivers * registry, int id1, int id2)
|
||||
@ -78,23 +79,26 @@ void OmniRigTransceiver::register_transceivers (TransceiverFactory::Transceivers
|
||||
(*registry)[OmniRig_transceiver_one_name] = TransceiverFactory::Capabilities {
|
||||
id1
|
||||
, TransceiverFactory::Capabilities::none // COM isn't serial or network
|
||||
, true // does PTT
|
||||
, false // doesn't select mic/data (use OmniRig config file)
|
||||
, true // can remote control RTS nd DTR
|
||||
, true // asynchronous interface
|
||||
, true // does PTT
|
||||
, false // doesn't select mic/data (use OmniRig config file)
|
||||
, true // can remote control RTS nd DTR
|
||||
, true // asynchronous interface
|
||||
};
|
||||
(*registry)[OmniRig_transceiver_two_name] = TransceiverFactory::Capabilities {
|
||||
id2
|
||||
, TransceiverFactory::Capabilities::none // COM isn't serial or network
|
||||
, true // does PTT
|
||||
, false // doesn't select mic/data (use OmniRig config file)
|
||||
, true // can remote control RTS nd DTR
|
||||
, true // asynchronous interface
|
||||
, true // does PTT
|
||||
, false // doesn't select mic/data (use OmniRig config file)
|
||||
, true // can remote control RTS nd DTR
|
||||
, true // asynchronous interface
|
||||
};
|
||||
}
|
||||
|
||||
OmniRigTransceiver::OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped, RigNumber n, TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port)
|
||||
: wrapped_ {std::move (wrapped)}
|
||||
OmniRigTransceiver::OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped,
|
||||
RigNumber n, TransceiverFactory::PTTMethod ptt_type,
|
||||
QString const& ptt_port, QObject * parent)
|
||||
: TransceiverBase {parent}
|
||||
, wrapped_ {std::move (wrapped)}
|
||||
, use_for_ptt_ {TransceiverFactory::PTT_method_CAT == ptt_type || ("CAT" == ptt_port && (TransceiverFactory::PTT_method_RTS == ptt_type || TransceiverFactory::PTT_method_DTR == ptt_type))}
|
||||
, ptt_type_ {ptt_type}
|
||||
, rig_number_ {n}
|
||||
@ -105,21 +109,17 @@ OmniRigTransceiver::OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped
|
||||
{
|
||||
}
|
||||
|
||||
OmniRigTransceiver::~OmniRigTransceiver ()
|
||||
int OmniRigTransceiver::do_start ()
|
||||
{
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_start ()
|
||||
{
|
||||
TRACE_CAT ("starting");
|
||||
wrapped_->start ();
|
||||
TRACE_CAT ("OmniRigTransceiver", "starting");
|
||||
if (wrapped_) wrapped_->start (0);
|
||||
|
||||
CoInitializeEx (nullptr, 0 /*COINIT_APARTMENTTHREADED*/); // required because Qt only does this for GUI thread
|
||||
|
||||
omni_rig_.reset (new OmniRig::OmniRigX {this});
|
||||
if (omni_rig_->isNull ())
|
||||
{
|
||||
TRACE_CAT ("failed to start COM server");
|
||||
TRACE_CAT ("OmniRigTransceiver", "failed to start COM server");
|
||||
throw_qstring (tr ("Failed to start OmniRig COM server"));
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ void OmniRigTransceiver::do_start ()
|
||||
, SIGNAL (CustomReply (int, QVariant const&, QVariant const&))
|
||||
, this, SLOT (handle_custom_reply (int, QVariant const&, QVariant const&)));
|
||||
|
||||
TRACE_CAT ("OmniRig s/w version:" << QString::number (omni_rig_->SoftwareVersion ()).toLocal8Bit ()
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig s/w version:" << QString::number (omni_rig_->SoftwareVersion ()).toLocal8Bit ()
|
||||
<< "i/f version:" << QString::number (omni_rig_->InterfaceVersion ()).toLocal8Bit ());
|
||||
|
||||
// fetch the interface of the RigX CoClass and instantiate a proxy object
|
||||
@ -155,18 +155,19 @@ void OmniRigTransceiver::do_start ()
|
||||
|
||||
Q_ASSERT (port_);
|
||||
Q_ASSERT (!port_->isNull ());
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig RTS state:" << port_->Rts ());
|
||||
|
||||
// if (!port_->Lock ()) // try to take exclusive use of the OmniRig serial port for PTT
|
||||
// {
|
||||
// throw_qstring (tr ("Failed to get exclusive use of %1" from OmniRig").arg (ptt_type));
|
||||
// }
|
||||
if (!port_->Lock ()) // try to take exclusive use of the OmniRig serial port for PTT
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "Failed to get exclusive use of serial port for PTT from OmniRig");
|
||||
}
|
||||
|
||||
// start off so we don't accidentally key the radio
|
||||
if (TransceiverFactory::PTT_method_DTR == ptt_type_)
|
||||
{
|
||||
port_->SetDtr (false);
|
||||
}
|
||||
else // RTS
|
||||
else // RTS
|
||||
{
|
||||
port_->SetRts (false);
|
||||
}
|
||||
@ -175,66 +176,81 @@ void OmniRigTransceiver::do_start ()
|
||||
readable_params_ = rig_->ReadableParams ();
|
||||
writable_params_ = rig_->WriteableParams ();
|
||||
|
||||
TRACE_CAT (QString {"OmniRig initial rig type: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig initial rig type: %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'))
|
||||
.arg (rig_number_).toLocal8Bit ());
|
||||
|
||||
TRACE_CAT ("OmniRig status:" << rig_->StatusStr ());
|
||||
|
||||
init_rig ();
|
||||
for (unsigned tries {0}; tries < 10; ++tries)
|
||||
{
|
||||
QThread::msleep (100); // wait until OmniRig polls the rig
|
||||
auto f = rig_->GetRxFrequency ();
|
||||
int resolution {0};
|
||||
if (f)
|
||||
{
|
||||
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 -55: resolution = -2; break; // 100Hz truncated
|
||||
case 45: resolution = 2; break; // 100Hz 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;
|
||||
}
|
||||
}
|
||||
throw_qstring (tr ("OmniRig: Initialization timed out"));
|
||||
return 0; // keep compiler happy
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_stop ()
|
||||
{
|
||||
QThread::msleep (200); // leave some time for pending
|
||||
// commands at the server end
|
||||
if (port_)
|
||||
{
|
||||
// port_->Unlock (); // release serial port
|
||||
port_->Unlock (); // release serial port
|
||||
port_->clear ();
|
||||
}
|
||||
rig_->clear ();
|
||||
omni_rig_->clear ();
|
||||
if (rig_) rig_->clear ();
|
||||
if (omni_rig_) omni_rig_->clear ();
|
||||
CoUninitialize ();
|
||||
wrapped_->stop ();
|
||||
TRACE_CAT ("stopped");
|
||||
if (wrapped_) wrapped_->stop ();
|
||||
TRACE_CAT ("OmniRigTransceiver", "stopped");
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::online_check ()
|
||||
{
|
||||
if (OmniRig::ST_ONLINE != rig_->Status ())
|
||||
{
|
||||
offline ("OmniRig rig went offline for more than 5 seconds");
|
||||
}
|
||||
else
|
||||
{
|
||||
init_rig ();
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::init_rig ()
|
||||
{
|
||||
if (OmniRig::ST_ONLINE != rig_->Status ())
|
||||
{
|
||||
QTimer::singleShot (5000, this, SLOT (online_check ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
update_rx_frequency (rig_->GetRxFrequency ());
|
||||
if (state ().split ())
|
||||
{
|
||||
TRACE_CAT ("set split");
|
||||
rig_->SetSplitMode (state ().frequency (), state ().tx_frequency ());
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("set simplex");
|
||||
rig_->SetSimplexMode (state ().frequency ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_sync (bool force_signal)
|
||||
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
|
||||
@ -247,13 +263,13 @@ void OmniRigTransceiver::do_sync (bool force_signal)
|
||||
|
||||
void OmniRigTransceiver::handle_COM_exception (int code, QString source, QString desc, QString help)
|
||||
{
|
||||
TRACE_CAT (QString::number (code) + " at " + source + ": " + desc + " (" + help + ')');
|
||||
TRACE_CAT ("OmniRigTransceiver", QString::number (code) + " at " + source + ": " + desc + " (" + help + ')');
|
||||
throw_qstring (tr ("OmniRig COM/OLE error: %1 at %2: %3 (%4)").arg (QString::number (code)).arg (source). arg (desc). arg (help));
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_visible_change ()
|
||||
{
|
||||
TRACE_CAT ("visibility change: visibility =" << omni_rig_->DialogVisible ());
|
||||
TRACE_CAT ("OmniRigTransceiver", "visibility change: visibility =" << omni_rig_->DialogVisible ());
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::handle_rig_type_change (int rig_number)
|
||||
@ -262,7 +278,7 @@ void OmniRigTransceiver::handle_rig_type_change (int rig_number)
|
||||
{
|
||||
readable_params_ = rig_->ReadableParams ();
|
||||
writable_params_ = rig_->WriteableParams ();
|
||||
TRACE_CAT (QString {"OmniRig rig type change to: %1 readable params = 0x%2 writable params = 0x%3 for rig %4"}
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig 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'))
|
||||
@ -275,11 +291,15 @@ void OmniRigTransceiver::handle_status_change (int rig_number)
|
||||
{
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
TRACE_CAT (QString {"OmniRig status change: new status for rig %1 = "}.arg (rig_number).toLocal8Bit () << rig_->StatusStr ().toLocal8Bit ());
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig status change: new status for rig %1 = "}.arg (rig_number).toLocal8Bit () << rig_->StatusStr ().toLocal8Bit ());
|
||||
if (OmniRig::ST_ONLINE != rig_->Status ())
|
||||
{
|
||||
QTimer::singleShot (5000, this, SLOT (online_check ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig frequency:" << rig_->GetRxFrequency ());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,16 +307,16 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
{
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
TRACE_CAT (QString {"OmniRig params change: params = 0x%1 for rig %2"}
|
||||
TRACE_CAT ("OmniRigTransceiver", QString {"OmniRig params change: params = 0x%1 for rig %2"}
|
||||
.arg (params, 8, 16, QChar ('0'))
|
||||
.arg (rig_number).toLocal8Bit ()
|
||||
<< "state before:" << state ());
|
||||
// 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
|
||||
// state_.online = true; // sometimes we don't get an initial
|
||||
// // OmniRig::ST_ONLINE status change
|
||||
// // event
|
||||
if (params & OmniRig::PM_VFOAA)
|
||||
{
|
||||
update_split (false);
|
||||
@ -481,7 +501,7 @@ void OmniRigTransceiver::handle_params_change (int rig_number, int params)
|
||||
update_complete ();
|
||||
send_update_signal_ = false;
|
||||
}
|
||||
TRACE_CAT ("OmniRig params change: state after:" << state ());
|
||||
TRACE_CAT ("OmniRigTransceiver", "OmniRig params change: state after:" << state ());
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,19 +512,19 @@ void OmniRigTransceiver::handle_custom_reply (int rig_number, QVariant const& co
|
||||
|
||||
if (rig_number_ == rig_number)
|
||||
{
|
||||
TRACE_CAT ("OmniRig custom command" << command.toString ().toLocal8Bit ()
|
||||
TRACE_CAT ("OmniRigTransceiver", "custom command" << command.toString ().toLocal8Bit ()
|
||||
<< "with reply" << reply.toString ().toLocal8Bit ()
|
||||
<< QString ("for rig %1").arg (rig_number).toLocal8Bit ());
|
||||
TRACE_CAT ("OmniRig rig number:" << rig_number_ << ':' << state ());
|
||||
TRACE_CAT ("OmniRigTransceiver", "rig number:" << rig_number_ << ':' << state ());
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_ptt (bool on)
|
||||
{
|
||||
TRACE_CAT (on << state ());
|
||||
TRACE_CAT ("OmniRigTransceiver", on << state ());
|
||||
if (use_for_ptt_ && TransceiverFactory::PTT_method_CAT == ptt_type_)
|
||||
{
|
||||
TRACE_CAT ("set PTT");
|
||||
TRACE_CAT ("OmniRigTransceiver", "set PTT");
|
||||
rig_->SetTx (on ? OmniRig::PM_TX : OmniRig::PM_RX);
|
||||
}
|
||||
else
|
||||
@ -513,19 +533,22 @@ void OmniRigTransceiver::do_ptt (bool on)
|
||||
{
|
||||
if (TransceiverFactory::PTT_method_RTS == ptt_type_)
|
||||
{
|
||||
TRACE_CAT ("set RTS");
|
||||
TRACE_CAT ("OmniRigTransceiver", "set RTS");
|
||||
port_->SetRts (on);
|
||||
}
|
||||
else // "DTR"
|
||||
else // "DTR"
|
||||
{
|
||||
TRACE_CAT ("set DTR");
|
||||
TRACE_CAT ("OmniRigTransceiver", "set DTR");
|
||||
port_->SetDtr (on);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("set PTT using basic transceiver");
|
||||
wrapped_->ptt (on);
|
||||
TRACE_CAT ("OmniRigTransceiver", "set PTT using basic transceiver");
|
||||
Q_ASSERT (wrapped_);
|
||||
TransceiverState new_state {wrapped_->state ()};
|
||||
new_state.ptt (on);
|
||||
wrapped_->set (new_state, 0);
|
||||
}
|
||||
if (state ().ptt () != on)
|
||||
{
|
||||
@ -536,12 +559,12 @@ void OmniRigTransceiver::do_ptt (bool on)
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_frequency (Frequency f, MODE m)
|
||||
void OmniRigTransceiver::do_frequency (Frequency f, MODE m, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT (f << state ());
|
||||
TRACE_CAT ("OmniRigTransceiver", f << state ());
|
||||
if (UNK != m)
|
||||
{
|
||||
do_mode (m, false);
|
||||
do_mode (m);
|
||||
}
|
||||
if (OmniRig::PM_FREQ & writable_params_)
|
||||
{
|
||||
@ -564,20 +587,20 @@ void OmniRigTransceiver::do_frequency (Frequency f, MODE m)
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_tx_frequency (Frequency tx, bool /* rationalise_mode */)
|
||||
void OmniRigTransceiver::do_tx_frequency (Frequency tx, bool /*no_ignore*/)
|
||||
{
|
||||
TRACE_CAT (tx << state ());
|
||||
TRACE_CAT ("OmniRigTransceiver", tx << state ());
|
||||
bool split {tx != 0};
|
||||
if (split)
|
||||
{
|
||||
TRACE_CAT ("set SPLIT mode on");
|
||||
TRACE_CAT ("OmniRigTransceiver", "set SPLIT mode on");
|
||||
rig_->SetSplitMode (state ().frequency (), tx);
|
||||
update_other_frequency (tx);
|
||||
update_split (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
TRACE_CAT ("set SPLIT mode off");
|
||||
TRACE_CAT ("OmniRigTransceiver", "set SPLIT mode off");
|
||||
rig_->SetSimplexMode (state ().frequency ());
|
||||
update_split (false);
|
||||
}
|
||||
@ -592,8 +615,8 @@ void OmniRigTransceiver::do_tx_frequency (Frequency tx, bool /* rationalise_mode
|
||||
}
|
||||
if (!((OmniRig::PM_VFOAB | OmniRig::PM_VFOBA | OmniRig::PM_SPLITON) & readable_params_))
|
||||
{
|
||||
TRACE_CAT ("setting SPLIT manually");
|
||||
update_split (split); // we can't read it so just set and
|
||||
TRACE_CAT ("OmniRigTransceiver", "setting SPLIT manually");
|
||||
update_split (split); // we can't read it so just set and
|
||||
// hope op doesn't change it
|
||||
notify = true;
|
||||
}
|
||||
@ -603,9 +626,9 @@ void OmniRigTransceiver::do_tx_frequency (Frequency tx, bool /* rationalise_mode
|
||||
}
|
||||
}
|
||||
|
||||
void OmniRigTransceiver::do_mode (MODE mode, bool /* rationalise */)
|
||||
void OmniRigTransceiver::do_mode (MODE mode)
|
||||
{
|
||||
TRACE_CAT (mode << state ());
|
||||
TRACE_CAT ("OmniRigTransceiver", mode << state ());
|
||||
// TODO: G4WJS OmniRig doesn't seem to have any capability of tracking/setting VFO B mode
|
||||
auto mapped = map_mode (mode);
|
||||
if (mapped & writable_params_)
|
||||
|
@ -30,19 +30,17 @@ public:
|
||||
enum RigNumber {One = 1, Two};
|
||||
|
||||
// takes ownership of wrapped Transceiver
|
||||
explicit OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped, RigNumber, TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port);
|
||||
~OmniRigTransceiver ();
|
||||
explicit OmniRigTransceiver (std::unique_ptr<TransceiverBase> wrapped, RigNumber, TransceiverFactory::PTTMethod ptt_type, QString const& ptt_port, QObject * parent = nullptr);
|
||||
|
||||
void do_start () override;
|
||||
int do_start () override;
|
||||
void do_stop () override;
|
||||
void do_frequency (Frequency, MODE) override;
|
||||
void do_tx_frequency (Frequency, bool rationalise_mode) override;
|
||||
void do_mode (MODE, bool rationalise) override;
|
||||
void do_frequency (Frequency, MODE, bool no_ignore) override;
|
||||
void do_tx_frequency (Frequency, bool no_ignore) override;
|
||||
void do_mode (MODE) override;
|
||||
void do_ptt (bool on) override;
|
||||
void do_sync (bool force_signal) override;
|
||||
void do_sync (bool force_signal, bool no_poll) override;
|
||||
|
||||
private:
|
||||
Q_SLOT void online_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);
|
||||
@ -50,12 +48,10 @@ private:
|
||||
Q_SLOT void handle_params_change (int rig_number, int params);
|
||||
Q_SLOT void handle_custom_reply (int, QVariant const& command, QVariant const& reply);
|
||||
|
||||
void init_rig ();
|
||||
|
||||
static MODE map_mode (OmniRig::RigParamX param);
|
||||
static OmniRig::RigParamX map_mode (MODE mode);
|
||||
|
||||
std::unique_ptr<TransceiverBase> wrapped_;
|
||||
std::unique_ptr<TransceiverBase> wrapped_; // may be null
|
||||
bool use_for_ptt_;
|
||||
TransceiverFactory::PTTMethod ptt_type_;
|
||||
QScopedPointer<OmniRig::OmniRigX> omni_rig_;
|
||||
|
@ -13,8 +13,9 @@ namespace
|
||||
unsigned const polls_to_stabilize {3};
|
||||
}
|
||||
|
||||
PollingTransceiver::PollingTransceiver (int poll_interval)
|
||||
: interval_ {poll_interval * 1000}
|
||||
PollingTransceiver::PollingTransceiver (int poll_interval, QObject * parent)
|
||||
: TransceiverBase {parent}
|
||||
, interval_ {poll_interval * 1000}
|
||||
, poll_timer_ {nullptr}
|
||||
, retries_ {0}
|
||||
{
|
||||
@ -26,12 +27,19 @@ void PollingTransceiver::start_timer ()
|
||||
{
|
||||
if (!poll_timer_)
|
||||
{
|
||||
poll_timer_ = new QTimer {this}; // pass ownership to QObject which handles destruction for us
|
||||
poll_timer_ = new QTimer {this}; // pass ownership to
|
||||
// QObject which handles
|
||||
// destruction for us
|
||||
|
||||
connect (poll_timer_, &QTimer::timeout, this, &PollingTransceiver::handle_timeout);
|
||||
connect (poll_timer_, &QTimer::timeout, this,
|
||||
&PollingTransceiver::handle_timeout);
|
||||
}
|
||||
poll_timer_->start (interval_);
|
||||
}
|
||||
else
|
||||
{
|
||||
stop_timer ();
|
||||
}
|
||||
}
|
||||
|
||||
void PollingTransceiver::stop_timer ()
|
||||
@ -77,7 +85,7 @@ void PollingTransceiver::do_post_frequency (Frequency f, MODE m)
|
||||
}
|
||||
}
|
||||
|
||||
void PollingTransceiver::do_post_tx_frequency (Frequency f, bool /* rationalize */)
|
||||
void PollingTransceiver::do_post_tx_frequency (Frequency f)
|
||||
{
|
||||
if (next_state_.tx_frequency () != f)
|
||||
{
|
||||
@ -89,7 +97,7 @@ void PollingTransceiver::do_post_tx_frequency (Frequency f, bool /* rationalize
|
||||
}
|
||||
}
|
||||
|
||||
void PollingTransceiver::do_post_mode (MODE m, bool /*rationalize_mode*/)
|
||||
void PollingTransceiver::do_post_mode (MODE m)
|
||||
{
|
||||
// we don't ever expect mode to goto to unknown
|
||||
if (m != UNK && next_state_.mode () != m)
|
||||
@ -106,7 +114,8 @@ void PollingTransceiver::do_post_ptt (bool p)
|
||||
{
|
||||
// update expected state with new PTT and set poll count
|
||||
next_state_.ptt (p);
|
||||
retries_ = 0; // fast feedback on PTT
|
||||
retries_ = polls_to_stabilize;
|
||||
//retries_ = 0; // fast feedback on PTT
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,10 +129,9 @@ bool PollingTransceiver::do_pre_update ()
|
||||
return true;
|
||||
}
|
||||
|
||||
void PollingTransceiver::do_sync (bool force_signal)
|
||||
void PollingTransceiver::do_sync (bool force_signal, bool no_poll)
|
||||
{
|
||||
poll (); // tell sub-classes to update our
|
||||
// state
|
||||
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
|
||||
@ -142,9 +150,9 @@ void PollingTransceiver::do_sync (bool force_signal)
|
||||
}
|
||||
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 sate has changed asynchronously
|
||||
// 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;
|
||||
}
|
||||
|
||||
@ -154,7 +162,7 @@ void PollingTransceiver::do_sync (bool force_signal)
|
||||
retries_ = 0;
|
||||
next_state_ = state ();
|
||||
last_signalled_state_ = state ();
|
||||
update_complete ();
|
||||
update_complete (true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +174,7 @@ void PollingTransceiver::handle_timeout ()
|
||||
// inform our parent of the failure via the offline() message
|
||||
try
|
||||
{
|
||||
do_sync (false);
|
||||
do_sync ();
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
|
@ -35,10 +35,11 @@ class PollingTransceiver
|
||||
Q_OBJECT; // for translation context
|
||||
|
||||
protected:
|
||||
explicit PollingTransceiver (int poll_interval); // in seconds
|
||||
explicit PollingTransceiver (int poll_interval, // in seconds
|
||||
QObject * parent);
|
||||
|
||||
protected:
|
||||
void do_sync (bool force_signal) override final;
|
||||
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.
|
||||
@ -46,9 +47,9 @@ protected:
|
||||
|
||||
void do_post_start () override final;
|
||||
void do_post_stop () override final;
|
||||
void do_post_frequency (Frequency, MODE = UNK) override final;
|
||||
void do_post_tx_frequency (Frequency, bool rationalize = true) override final;
|
||||
void do_post_mode (MODE, bool rationalize = true) override final;
|
||||
void do_post_frequency (Frequency, MODE) override final;
|
||||
void do_post_tx_frequency (Frequency) override final;
|
||||
void do_post_mode (MODE) override final;
|
||||
void do_post_ptt (bool = true) override final;
|
||||
bool do_pre_update () override final;
|
||||
|
||||
|
@ -10,8 +10,8 @@ QDebug operator << (QDebug d, Transceiver::TransceiverState const& s)
|
||||
{
|
||||
d.nospace ()
|
||||
<< "Transceiver::TransceiverState(online: " << (s.online_ ? "yes" : "no")
|
||||
<< " Frequency {" << s.frequency_[0] << "Hz, " << s.frequency_[1] << "Hz} " << s.mode_
|
||||
<< "; SPLIT: " << (Transceiver::TransceiverState::on == s.split_ ? "on" : Transceiver::TransceiverState::off == s.split_ ? "off" : "unknown")
|
||||
<< " Frequency {" << s.rx_frequency_ << "Hz, " << s.tx_frequency_ << "Hz} " << s.mode_
|
||||
<< "; SPLIT: " << (Transceiver::TransceiverState::Split::on == s.split_ ? "on" : Transceiver::TransceiverState::Split::off == s.split_ ? "off" : "unknown")
|
||||
<< "; PTT: " << (s.ptt_ ? "on" : "off")
|
||||
<< ')';
|
||||
return d.space ();
|
||||
@ -26,8 +26,8 @@ ENUM_CONVERSION_OPS_IMPL (Transceiver, MODE);
|
||||
bool operator != (Transceiver::TransceiverState const& lhs, Transceiver::TransceiverState const& rhs)
|
||||
{
|
||||
return lhs.online_ != rhs.online_
|
||||
|| lhs.frequency_[0] != rhs.frequency_[0]
|
||||
|| lhs.frequency_[1] != rhs.frequency_[1]
|
||||
|| lhs.rx_frequency_ != rhs.rx_frequency_
|
||||
|| lhs.tx_frequency_ != rhs.tx_frequency_
|
||||
|| lhs.mode_ != rhs.mode_
|
||||
|| lhs.split_ != rhs.split_
|
||||
|| lhs.ptt_ != rhs.ptt_;
|
||||
|
@ -16,9 +16,9 @@ class QString;
|
||||
//
|
||||
// Responsibilities
|
||||
//
|
||||
// Provides Qt slots to set the frequency, mode and PTT of some
|
||||
// transceiver. They are Qt slots so that they may be invoked across
|
||||
// a thread boundary.
|
||||
// Provides a Qt slot to set the frequency, mode and PTT of some
|
||||
// transceiver. This is a Qt slot so that it may be invoked across a
|
||||
// thread boundary.
|
||||
//
|
||||
// Provides a synchronisation Qt slot which should be implemented in
|
||||
// sub-classes in such a way that normal operation of the rig is not
|
||||
@ -58,14 +58,10 @@ public:
|
||||
using Frequency = Radio::Frequency;
|
||||
|
||||
protected:
|
||||
Transceiver ()
|
||||
{
|
||||
}
|
||||
Transceiver (QObject * parent) : QObject {parent} {}
|
||||
|
||||
public:
|
||||
virtual ~Transceiver ()
|
||||
{
|
||||
}
|
||||
virtual ~Transceiver () {}
|
||||
|
||||
enum MODE {UNK, CW, CW_R, USB, LSB, FSK, FSK_R, DIG_U, DIG_L, AM, FM, DIG_FM};
|
||||
Q_ENUM (MODE)
|
||||
@ -79,33 +75,34 @@ public:
|
||||
public:
|
||||
TransceiverState ()
|
||||
: online_ {false}
|
||||
, frequency_ {0, 0}
|
||||
, rx_frequency_ {0}
|
||||
, tx_frequency_ {0}
|
||||
, mode_ {UNK}
|
||||
, split_ {unknown}
|
||||
, split_ {Split::unknown}
|
||||
, ptt_ {false}
|
||||
{
|
||||
}
|
||||
|
||||
bool online () const {return online_;}
|
||||
Frequency frequency () const {return frequency_[0];}
|
||||
Frequency tx_frequency () const {return frequency_[1];}
|
||||
bool split () const {return on == split_;}
|
||||
bool compare_split (bool with) const {return split_ == (with ? on : off);}
|
||||
Frequency frequency () const {return rx_frequency_;}
|
||||
Frequency tx_frequency () const {return tx_frequency_;}
|
||||
bool split () const {return Split::on == split_;}
|
||||
MODE mode () const {return mode_;}
|
||||
bool ptt () const {return ptt_;}
|
||||
|
||||
void online (bool state) {online_ = state;}
|
||||
void frequency (Frequency f) {frequency_[0] = f;}
|
||||
void tx_frequency (Frequency f) {frequency_[1] = f;}
|
||||
void split (bool state) {split_ = state ? on : off;}
|
||||
void frequency (Frequency f) {rx_frequency_ = f;}
|
||||
void tx_frequency (Frequency f) {tx_frequency_ = f;}
|
||||
void split (bool state) {split_ = state ? Split::on : Split::off;}
|
||||
void mode (MODE m) {mode_ = m;}
|
||||
void ptt (bool state) {ptt_ = state;}
|
||||
|
||||
private:
|
||||
bool online_;
|
||||
Frequency frequency_[2]; // [0] -> Rx; [1] -> Other
|
||||
Frequency rx_frequency_;
|
||||
Frequency tx_frequency_; // 0 means use Rx
|
||||
MODE mode_;
|
||||
enum {unknown, off, on} split_;
|
||||
enum class Split {unknown, off, on} split_;
|
||||
bool ptt_;
|
||||
// Don't forget to update the debug print and != operator if you
|
||||
// add more members here
|
||||
@ -115,39 +112,42 @@ public:
|
||||
};
|
||||
|
||||
//
|
||||
// The following slots and signals are expected to all run in the
|
||||
// same thread which is not necessarily the main GUI thread. It is
|
||||
// up to the client of the Transceiver class to organise the
|
||||
// The following slots and signals are expected to all run in the
|
||||
// same thread which is not necessarily the main GUI thread. It is
|
||||
// up to the client of the Transceiver class to organise the
|
||||
// allocation to a thread and the lifetime of the object instances.
|
||||
//
|
||||
|
||||
// Apply state changes to the rig. The sequence_number parameter
|
||||
// will be included in any status updates generated after this
|
||||
// transaction is processed. The sequence number may be used to
|
||||
// ignore any status updates until the results of this transaction
|
||||
// have been processed thus avoiding any unwanted "ping-pong" due to
|
||||
// signals crossing in transit.
|
||||
Q_SLOT virtual void set (Transceiver::TransceiverState const&,
|
||||
unsigned sequence_number) noexcept = 0;
|
||||
|
||||
// Connect and disconnect.
|
||||
Q_SLOT virtual void start () noexcept = 0;
|
||||
Q_SLOT virtual void stop (bool reset_split = false) noexcept = 0;
|
||||
Q_SLOT virtual void start (unsigned sequence_number) noexcept = 0;
|
||||
Q_SLOT virtual void stop () noexcept = 0;
|
||||
|
||||
// Set frequency in Hertz.
|
||||
Q_SLOT virtual void frequency (Frequency, MODE = UNK) noexcept = 0;
|
||||
|
||||
// Setting a non-zero TX frequency means split operation, the value
|
||||
// zero means simplex operation.
|
||||
//
|
||||
// Rationalise_mode means ensure TX uses same mode as RX.
|
||||
Q_SLOT virtual void tx_frequency (Frequency tx = 0, bool rationalise_mode = true) noexcept = 0;
|
||||
|
||||
// Set mode.
|
||||
// Rationalise means ensure TX uses same mode as RX.
|
||||
Q_SLOT virtual void mode (MODE, bool rationalise = true) noexcept = 0;
|
||||
|
||||
// Set/unset PTT.
|
||||
Q_SLOT virtual void ptt (bool = true) noexcept = 0;
|
||||
|
||||
// Attempt to re-synchronise or query state.
|
||||
// Force_signal guarantees a update or failure signal.
|
||||
Q_SLOT virtual void sync (bool force_signal = false) noexcept = 0;
|
||||
|
||||
// asynchronous status updates
|
||||
Q_SIGNAL void update (Transceiver::TransceiverState) const;
|
||||
Q_SIGNAL void failure (QString reason) const;
|
||||
//
|
||||
|
||||
// 0 - 1Hz
|
||||
// 1 - 10Hz rounded
|
||||
// -1 - 10Hz truncated
|
||||
// 2 - 100Hz rounded
|
||||
// -2 - 100Hz truncated
|
||||
Q_SIGNAL void resolution (int);
|
||||
|
||||
// rig state changed
|
||||
Q_SIGNAL void update (Transceiver::TransceiverState const&,
|
||||
unsigned sequence_number) const;
|
||||
|
||||
// something went wrong - not recoverable, start new instance
|
||||
Q_SIGNAL void failure (QString const& reason) const;
|
||||
|
||||
// Ready to be destroyed.
|
||||
Q_SIGNAL void finished () const;
|
||||
|
@ -14,29 +14,15 @@ namespace
|
||||
auto const unexpected = TransceiverBase::tr ("Unexpected rig error");
|
||||
}
|
||||
|
||||
void TransceiverBase::start () noexcept
|
||||
void TransceiverBase::start (unsigned sequence_number) noexcept
|
||||
{
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
if (state_.online ())
|
||||
{
|
||||
try
|
||||
{
|
||||
// try and ensure PTT isn't left set
|
||||
do_ptt (false);
|
||||
do_post_ptt (false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// don't care about exceptions
|
||||
}
|
||||
do_stop ();
|
||||
do_post_stop ();
|
||||
}
|
||||
do_start ();
|
||||
do_post_start ();
|
||||
state_.online (true);
|
||||
may_update u {this, true};
|
||||
shutdown ();
|
||||
startup ();
|
||||
last_sequence_number_ = sequence_number;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
@ -52,33 +38,138 @@ void TransceiverBase::start () noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::stop (bool reset_split) noexcept
|
||||
void TransceiverBase::set (TransceiverState const& s,
|
||||
unsigned sequence_number) noexcept
|
||||
{
|
||||
TRACE_CAT ("TransceiverBase", "#:" << sequence_number << s);
|
||||
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
may_update u {this, true};
|
||||
bool was_online {requested_.online ()};
|
||||
if (!s.online () && was_online)
|
||||
{
|
||||
shutdown ();
|
||||
}
|
||||
else if (s.online () && !was_online)
|
||||
{
|
||||
shutdown ();
|
||||
startup ();
|
||||
}
|
||||
if (requested_.online ())
|
||||
{
|
||||
bool ptt_on {false};
|
||||
bool ptt_off {false};
|
||||
if (s.ptt () != requested_.ptt ())
|
||||
{
|
||||
ptt_on = s.ptt ();
|
||||
ptt_off = !s.ptt ();
|
||||
}
|
||||
if (ptt_off)
|
||||
{
|
||||
do_ptt (false);
|
||||
do_post_ptt (false);
|
||||
QThread::msleep (100); // some rigs cannot process CAT
|
||||
// commands while switching from
|
||||
// Tx to Rx
|
||||
}
|
||||
if ((s.frequency () != requested_.frequency () // and QSY
|
||||
|| (s.mode () != UNK && s.mode () != requested_.mode ())) // or mode change
|
||||
|| ptt_off) // or just returned to rx
|
||||
{
|
||||
do_frequency (s.frequency (), s.mode (), ptt_off);
|
||||
do_post_frequency (s.frequency (), s.mode ());
|
||||
|
||||
// record what actually changed
|
||||
requested_.frequency (actual_.frequency ());
|
||||
requested_.mode (actual_.mode ());
|
||||
}
|
||||
if (!s.tx_frequency () || s.tx_frequency () > 10000) // ignore bogus startup values
|
||||
{
|
||||
if ((s.tx_frequency () != requested_.tx_frequency () // and QSY
|
||||
|| (s.mode () != UNK && s.mode () != requested_.mode ())) // or mode change
|
||||
// || s.split () != requested_.split ())) // or split change
|
||||
|| ptt_on) // or about to tx
|
||||
{
|
||||
do_tx_frequency (s.tx_frequency (), ptt_on);
|
||||
do_post_tx_frequency (s.tx_frequency ());
|
||||
|
||||
// record what actually changed
|
||||
requested_.tx_frequency (actual_.tx_frequency ());
|
||||
requested_.split (actual_.split ());
|
||||
}
|
||||
}
|
||||
if (ptt_on)
|
||||
{
|
||||
do_ptt (true);
|
||||
do_post_ptt (true);
|
||||
QThread::msleep (100); // some rigs cannot process CAT
|
||||
// commands while switching from
|
||||
// Rx to Tx
|
||||
}
|
||||
|
||||
// record what actually changed
|
||||
requested_.ptt (actual_.ptt ());
|
||||
}
|
||||
last_sequence_number_ = sequence_number;
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
{
|
||||
offline (message);
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::startup ()
|
||||
{
|
||||
Q_EMIT resolution (do_start ());
|
||||
do_post_start ();
|
||||
actual_.online (true);
|
||||
requested_.online (true);
|
||||
}
|
||||
|
||||
void TransceiverBase::shutdown ()
|
||||
{
|
||||
may_update u {this};
|
||||
if (requested_.online ())
|
||||
{
|
||||
try
|
||||
{
|
||||
// try and ensure PTT isn't left set
|
||||
do_ptt (false);
|
||||
do_post_ptt (false);
|
||||
if (requested_.split ())
|
||||
{
|
||||
// try and reset split mode
|
||||
do_tx_frequency (0, true);
|
||||
do_post_tx_frequency (0);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// don't care about exceptions
|
||||
}
|
||||
}
|
||||
do_stop ();
|
||||
do_post_stop ();
|
||||
actual_.online (false);
|
||||
requested_.online (false);
|
||||
}
|
||||
|
||||
void TransceiverBase::stop () noexcept
|
||||
{
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
if (state_.online ())
|
||||
{
|
||||
try
|
||||
{
|
||||
// try and ensure PTT isn't left set
|
||||
do_ptt (false);
|
||||
do_post_ptt (false);
|
||||
if (reset_split)
|
||||
{
|
||||
// try and reset split mode
|
||||
do_tx_frequency (0, false);
|
||||
do_post_tx_frequency (0, false);
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// don't care about exceptions
|
||||
}
|
||||
}
|
||||
do_stop ();
|
||||
do_post_stop ();
|
||||
state_.online (false);
|
||||
shutdown ();
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
@ -98,206 +189,82 @@ void TransceiverBase::stop (bool reset_split) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::frequency (Frequency f, MODE m) noexcept
|
||||
{
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
if (state_.online ())
|
||||
{
|
||||
do_frequency (f, m);
|
||||
do_post_frequency (f, m);
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
{
|
||||
offline (message);
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::tx_frequency (Frequency tx, bool rationalise_mode) noexcept
|
||||
{
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
if (state_.online ())
|
||||
{
|
||||
do_tx_frequency (tx, rationalise_mode);
|
||||
do_post_tx_frequency (tx, rationalise_mode);
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
{
|
||||
offline (message);
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::mode (MODE m, bool rationalise) noexcept
|
||||
{
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
if (state_.online ())
|
||||
{
|
||||
do_mode (m, rationalise);
|
||||
do_post_mode (m, rationalise);
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
{
|
||||
offline (message);
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::ptt (bool on) noexcept
|
||||
{
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
if (state_.online ())
|
||||
{
|
||||
do_ptt (on);
|
||||
do_post_ptt (on);
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
{
|
||||
offline (message);
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::sync (bool force_signal) noexcept
|
||||
{
|
||||
QString message;
|
||||
try
|
||||
{
|
||||
if (state_.online ())
|
||||
{
|
||||
do_sync (force_signal);
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
message = e.what ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
message = unexpected;
|
||||
}
|
||||
if (!message.isEmpty ())
|
||||
{
|
||||
offline (message);
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::update_rx_frequency (Frequency rx)
|
||||
{
|
||||
state_.frequency (rx);
|
||||
actual_.frequency (rx);
|
||||
requested_.frequency (rx); // track rig changes
|
||||
}
|
||||
|
||||
void TransceiverBase::update_other_frequency (Frequency tx)
|
||||
{
|
||||
state_.tx_frequency (tx);
|
||||
actual_.tx_frequency (tx);
|
||||
}
|
||||
|
||||
void TransceiverBase::update_split (bool state)
|
||||
{
|
||||
state_.split (state);
|
||||
actual_.split (state);
|
||||
}
|
||||
|
||||
void TransceiverBase::update_mode (MODE m)
|
||||
{
|
||||
state_.mode (m);
|
||||
actual_.mode (m);
|
||||
}
|
||||
|
||||
void TransceiverBase::update_PTT (bool state)
|
||||
{
|
||||
auto prior = state_.ptt ();
|
||||
state_.ptt (state);
|
||||
if (state != prior)
|
||||
{
|
||||
// always signal PTT changes because some MainWindow logic
|
||||
// depends on it
|
||||
update_complete ();
|
||||
}
|
||||
actual_.ptt (state);
|
||||
}
|
||||
|
||||
void TransceiverBase::updated ()
|
||||
{
|
||||
if (do_pre_update ())
|
||||
{
|
||||
Q_EMIT update (state_);
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::update_complete ()
|
||||
bool TransceiverBase::maybe_low_resolution (Radio::Frequency low_res,
|
||||
Radio::Frequency high_res)
|
||||
{
|
||||
// Use a timer to ensure that the calling function completes before
|
||||
// the Transceiver::update signal is triggered.
|
||||
QTimer::singleShot (0, this, SLOT (updated ()));
|
||||
if (resolution_ != Resolution::truncate
|
||||
&& low_res == (high_res + 5) / 10 * 10) // rounded to 10's
|
||||
{
|
||||
resolution_ = Resolution::round;
|
||||
return true;
|
||||
}
|
||||
if (resolution_ != Resolution::round
|
||||
&& low_res == high_res / 10 * 10) // truncated to 10's
|
||||
{
|
||||
resolution_ = Resolution::truncate;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (resolution_ != Resolution::truncate
|
||||
&& low_res == (high_res + 50) / 100 * 100) // rounded to 100's
|
||||
{
|
||||
resolution_ = Resolution::round;
|
||||
return true;
|
||||
}
|
||||
if (resolution_ != Resolution::round
|
||||
&& low_res == high_res / 100 * 100) // truncated to 100's
|
||||
{
|
||||
resolution_ = Resolution::truncate;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TransceiverBase::update_complete (bool force_signal)
|
||||
{
|
||||
if ((do_pre_update () && actual_ != last_) || force_signal)
|
||||
{
|
||||
Q_EMIT update (actual_, last_sequence_number_);
|
||||
last_ = actual_;
|
||||
}
|
||||
}
|
||||
|
||||
void TransceiverBase::offline (QString const& reason)
|
||||
{
|
||||
QString message;
|
||||
Q_EMIT failure (reason);
|
||||
try
|
||||
{
|
||||
if (state_.online ())
|
||||
{
|
||||
try
|
||||
{
|
||||
// try and ensure PTT isn't left set
|
||||
do_ptt (false);
|
||||
do_post_ptt (false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// don't care about exceptions
|
||||
}
|
||||
}
|
||||
do_stop ();
|
||||
do_post_stop ();
|
||||
state_.online (false);
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
message = e.what ();
|
||||
shutdown ();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
message = unexpected;
|
||||
// don't care
|
||||
}
|
||||
Q_EMIT failure (reason + '\n' + message);
|
||||
}
|
||||
|
@ -60,20 +60,29 @@ class TransceiverBase
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
private:
|
||||
enum class Resolution {accurate, round, truncate};
|
||||
|
||||
protected:
|
||||
TransceiverBase () = default;
|
||||
TransceiverBase (QObject * parent)
|
||||
: Transceiver {parent}
|
||||
, resolution_ {Resolution::accurate}
|
||||
, last_sequence_number_ {0}
|
||||
{}
|
||||
|
||||
public:
|
||||
//
|
||||
// Implement the Transceiver abstract interface.
|
||||
//
|
||||
void start () noexcept override final;
|
||||
void stop (bool reset_split = false) noexcept override final;
|
||||
void frequency (Frequency rx, MODE = UNK) noexcept override final;
|
||||
void tx_frequency (Frequency tx, bool rationalise_mode) noexcept override final;
|
||||
void mode (MODE, bool rationalise) noexcept override final;
|
||||
void ptt (bool) noexcept override final;
|
||||
void sync (bool force_signal) noexcept override final;
|
||||
void start (unsigned sequence_number) noexcept override final;
|
||||
void set (TransceiverState const&,
|
||||
unsigned sequence_number) noexcept override final;
|
||||
void stop () noexcept override final;
|
||||
|
||||
//
|
||||
// Query operations
|
||||
//
|
||||
TransceiverState const& state () const {return actual_;}
|
||||
|
||||
protected:
|
||||
//
|
||||
@ -82,32 +91,32 @@ protected:
|
||||
struct error
|
||||
: public std::runtime_error
|
||||
{
|
||||
error (char const * const msg) : std::runtime_error (msg) {}
|
||||
error (QString const& msg) : std::runtime_error (msg.toStdString ()) {}
|
||||
explicit error (char const * const msg) : std::runtime_error (msg) {}
|
||||
explicit error (QString const& msg) : std::runtime_error (msg.toStdString ()) {}
|
||||
};
|
||||
|
||||
// Template methods that sub classes implement to do what they need to do.
|
||||
//
|
||||
// These methods may throw exceptions to signal errors.
|
||||
virtual void do_start () = 0;
|
||||
virtual int do_start () = 0; // returns resolution, See Transceiver::resolution
|
||||
virtual void do_post_start () {}
|
||||
|
||||
virtual void do_stop () = 0;
|
||||
virtual void do_post_stop () {}
|
||||
|
||||
virtual void do_frequency (Frequency rx, MODE = UNK) = 0;
|
||||
virtual void do_post_frequency (Frequency, MODE = UNK) {}
|
||||
virtual void do_frequency (Frequency, MODE, bool no_ignore) = 0;
|
||||
virtual void do_post_frequency (Frequency, MODE) {}
|
||||
|
||||
virtual void do_tx_frequency (Frequency tx = 0u, bool rationalise_mode = false) = 0;
|
||||
virtual void do_post_tx_frequency (Frequency = 0u, bool /* rationalise_mode */ = false) {}
|
||||
virtual void do_tx_frequency (Frequency, bool no_ignore) = 0;
|
||||
virtual void do_post_tx_frequency (Frequency) {}
|
||||
|
||||
virtual void do_mode (MODE, bool rationalise = true) = 0;
|
||||
virtual void do_post_mode (MODE, bool /* rationalise */ = true) {}
|
||||
virtual void do_mode (MODE) = 0;
|
||||
virtual void do_post_mode (MODE) {}
|
||||
|
||||
virtual void do_ptt (bool = true) = 0;
|
||||
virtual void do_post_ptt (bool = true) {}
|
||||
|
||||
virtual void do_sync (bool force_signal = false) = 0;
|
||||
virtual void do_sync (bool force_signal = false, bool no_poll = false) = 0;
|
||||
|
||||
virtual bool do_pre_update () {return true;}
|
||||
|
||||
@ -119,31 +128,48 @@ protected:
|
||||
void update_PTT (bool = true);
|
||||
|
||||
// Calling this eventually triggers the Transceiver::update(State) signal.
|
||||
void update_complete ();
|
||||
void update_complete (bool force_signal = false);
|
||||
|
||||
// sub class may asynchronously take the rig offline by calling this
|
||||
void offline (QString const& reason);
|
||||
|
||||
// and query state with this one
|
||||
TransceiverState const& state () const {return state_;}
|
||||
|
||||
private:
|
||||
Q_SLOT void updated ();
|
||||
void startup ();
|
||||
void shutdown ();
|
||||
bool maybe_low_resolution (Frequency low_res, Frequency high_res);
|
||||
|
||||
TransceiverState state_;
|
||||
// use this convenience class to notify in update methods
|
||||
class may_update
|
||||
{
|
||||
public:
|
||||
explicit may_update (TransceiverBase * self, bool force_signal = false)
|
||||
: self_ {self}
|
||||
, force_signal_ {force_signal}
|
||||
{}
|
||||
~may_update () {self_->update_complete (force_signal_);}
|
||||
private:
|
||||
TransceiverBase * self_;
|
||||
bool force_signal_;
|
||||
};
|
||||
|
||||
TransceiverState requested_;
|
||||
TransceiverState actual_;
|
||||
TransceiverState last_;
|
||||
Resolution resolution_; // rig accuracy
|
||||
unsigned last_sequence_number_; // from set state operation
|
||||
};
|
||||
|
||||
// some trace macros
|
||||
#if WSJT_TRACE_CAT
|
||||
#define TRACE_CAT(MSG) qDebug () << __PRETTY_FUNCTION__ << MSG
|
||||
#define TRACE_CAT(FAC, MSG) qDebug () << QString {"%1::%2:"}.arg ((FAC)).arg (__func__) << MSG
|
||||
#else
|
||||
#define TRACE_CAT(MSG)
|
||||
#define TRACE_CAT(FAC, MSG)
|
||||
#endif
|
||||
|
||||
#if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS
|
||||
#define TRACE_CAT_POLL(MSG) qDebug () << __PRETTY_FUNCTION__ << MSG
|
||||
#define TRACE_CAT_POLL(FAC, MSG) qDebug () << QString {"%1::%2:"}.arg ((FAC)).arg (__func__) << MSG
|
||||
#else
|
||||
#define TRACE_CAT_POLL(MSG)
|
||||
#define TRACE_CAT_POLL(FAC, MSG)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -82,36 +82,44 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
{
|
||||
case CommanderId:
|
||||
{
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
std::unique_ptr<TransceiverBase> basic_transceiver {new HamlibTransceiver {params.ptt_type, params.ptt_port}};
|
||||
if (target_thread)
|
||||
std::unique_ptr<TransceiverBase> basic_transceiver;
|
||||
if (PTT_method_CAT != params.ptt_type)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
basic_transceiver.reset (new HamlibTransceiver {params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
|
||||
// wrap the basic Transceiver object instance with a decorator object that talks to DX Lab Suite Commander
|
||||
result.reset (new DXLabSuiteCommanderTransceiver {std::move (basic_transceiver), params.network_port, PTT_method_CAT == params.ptt_type, params.poll_interval});
|
||||
if (target_thread)
|
||||
{
|
||||
result.get ()->moveToThread (target_thread);
|
||||
result->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HRDId:
|
||||
{
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
std::unique_ptr<TransceiverBase> basic_transceiver {new HamlibTransceiver {params.ptt_type, params.ptt_port}};
|
||||
if (target_thread)
|
||||
std::unique_ptr<TransceiverBase> basic_transceiver;
|
||||
if (PTT_method_CAT != params.ptt_type)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
basic_transceiver.reset (new HamlibTransceiver {params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
|
||||
// wrap the basic Transceiver object instance with a decorator object that talks to ham Radio Deluxe
|
||||
result.reset (new HRDTransceiver {std::move (basic_transceiver), params.network_port, PTT_method_CAT == params.ptt_type, params.poll_interval});
|
||||
result.reset (new HRDTransceiver {std::move (basic_transceiver), params.network_port, PTT_method_CAT == params.ptt_type, params.poll_interval, params.set_rig_mode});
|
||||
if (target_thread)
|
||||
{
|
||||
result.get ()->moveToThread (target_thread);
|
||||
result->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -119,36 +127,44 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
#if defined (WIN32)
|
||||
case OmniRigOneId:
|
||||
{
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
std::unique_ptr<TransceiverBase> basic_transceiver {new HamlibTransceiver {params.ptt_type, params.ptt_port}};
|
||||
if (target_thread)
|
||||
std::unique_ptr<TransceiverBase> basic_transceiver;
|
||||
if (PTT_method_CAT != params.ptt_type && "CAT" != params.ptt_port)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
basic_transceiver.reset (new HamlibTransceiver {params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
|
||||
// wrap the basic Transceiver object instance with a decorator object that talks to OmniRig rig one
|
||||
result.reset (new OmniRigTransceiver {std::move (basic_transceiver), OmniRigTransceiver::One, params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
result.get ()->moveToThread (target_thread);
|
||||
result->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OmniRigTwoId:
|
||||
{
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
std::unique_ptr<TransceiverBase> basic_transceiver {new HamlibTransceiver {params.ptt_type, params.ptt_port}};
|
||||
if (target_thread)
|
||||
std::unique_ptr<TransceiverBase> basic_transceiver;
|
||||
if (PTT_method_CAT != params.ptt_type && "CAT" != params.ptt_port)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
// we start with a dummy HamlibTransceiver object instance that can support direct PTT
|
||||
basic_transceiver.reset (new HamlibTransceiver {params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
basic_transceiver.get ()->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
|
||||
// wrap the basic Transceiver object instance with a decorator object that talks to OmniRig rig two
|
||||
result.reset (new OmniRigTransceiver {std::move (basic_transceiver), OmniRigTransceiver::Two, params.ptt_type, params.ptt_port});
|
||||
if (target_thread)
|
||||
{
|
||||
result.get ()->moveToThread (target_thread);
|
||||
result->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -158,7 +174,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
result.reset (new HamlibTransceiver {supported_transceivers ()[params.rig_name].model_number_, params});
|
||||
if (target_thread)
|
||||
{
|
||||
result.get ()->moveToThread (target_thread);
|
||||
result->moveToThread (target_thread);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -169,7 +185,7 @@ std::unique_ptr<Transceiver> TransceiverFactory::create (ParameterPack const& pa
|
||||
result.reset (new EmulateSplitTransceiver {std::move (result)});
|
||||
if (target_thread)
|
||||
{
|
||||
result.get ()->moveToThread (target_thread);
|
||||
result->moveToThread (target_thread);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,17 +104,18 @@ public:
|
||||
StopBits stop_bits;
|
||||
Handshake handshake;
|
||||
bool force_dtr;
|
||||
bool dtr_high; // to power interface
|
||||
bool dtr_high; // to power interface
|
||||
bool force_rts;
|
||||
bool rts_high; // to power interface
|
||||
PTTMethod ptt_type; // "CAT" | "DTR" | "RTS" | "VOX"
|
||||
TXAudioSource audio_source; // some rigs allow audio routing
|
||||
// to Mic/Data connector
|
||||
SplitMode split_mode; // how to support split TX mode
|
||||
QString ptt_port; // serial port device name or special
|
||||
// value "CAT"
|
||||
int poll_interval; // in seconds for interfaces that
|
||||
// require polling for state changes
|
||||
bool rts_high; // to power interface
|
||||
PTTMethod ptt_type; // "CAT" | "DTR" | "RTS" | "VOX"
|
||||
TXAudioSource audio_source; // some rigs allow audio routing
|
||||
// to Mic/Data connector
|
||||
bool set_rig_mode; // handle rig mode when required
|
||||
SplitMode split_mode; // how to support split TX mode
|
||||
QString ptt_port; // serial port device name or special
|
||||
// value "CAT"
|
||||
int poll_interval; // in seconds for interfaces that
|
||||
// require polling for state changes
|
||||
|
||||
bool operator == (ParameterPack const& rhs) const
|
||||
{
|
||||
@ -132,9 +133,11 @@ public:
|
||||
&& rhs.rts_high == rts_high
|
||||
&& rhs.ptt_type == ptt_type
|
||||
&& rhs.audio_source == audio_source
|
||||
&& rhs.set_rig_mode == set_rig_mode
|
||||
&& rhs.split_mode == split_mode
|
||||
&& rhs.ptt_port == ptt_port
|
||||
&& rhs.poll_interval == poll_interval;
|
||||
&& rhs.poll_interval == poll_interval
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
|
190
astro.cpp
190
astro.cpp
@ -20,30 +20,37 @@
|
||||
#include "ui_astro.h"
|
||||
#include "moc_astro.cpp"
|
||||
|
||||
|
||||
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,
|
||||
int len1, int len2, int len3, int len4);
|
||||
}
|
||||
|
||||
Astro::Astro(QSettings * settings, Configuration const * configuration, QWidget * parent)
|
||||
: QWidget {parent, Qt::Tool | Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint | Qt::MSWindowsFixedSizeDialogHint}
|
||||
: QDialog {parent, Qt::WindowTitleHint}
|
||||
, settings_ {settings}
|
||||
, configuration_ {configuration}
|
||||
, ui_ {new Ui::Astro}
|
||||
, m_bRxAudioTrack {false}
|
||||
, m_bTxAudioTrack {false}
|
||||
, m_bTrackVFO {true}
|
||||
, m_DopplerMethod {0}
|
||||
, m_kHz {0}
|
||||
, m_Hz {0}
|
||||
, m_stepHz {1}
|
||||
{
|
||||
ui_->setupUi (this);
|
||||
setWindowTitle (QApplication::applicationName () + " - " + tr ("Astronomical Data"));
|
||||
setStyleSheet ("QWidget {background: white;}");
|
||||
connect (ui_->cbDopplerTracking, &QAbstractButton::toggled, ui_->doppler_widget, &QWidget::setVisible);
|
||||
connect (ui_->cbDopplerTracking, &QAbstractButton::toggled, this, &Astro::doppler_tracking_toggled);
|
||||
read_settings ();
|
||||
ui_->text_label->clear ();
|
||||
}
|
||||
|
||||
Astro::~Astro ()
|
||||
{
|
||||
ui_->cbDopplerTracking->setChecked (false);
|
||||
Q_EMIT tracking_update ();
|
||||
if (isVisible ()) write_settings ();
|
||||
}
|
||||
|
||||
@ -56,40 +63,30 @@ void Astro::closeEvent (QCloseEvent * e)
|
||||
void Astro::read_settings ()
|
||||
{
|
||||
SettingsGroup g (settings_, "Astro");
|
||||
ui_->cbDopplerTracking->setChecked (settings_->value ("DopplerTracking",false).toBool ());
|
||||
ui_->doppler_widget->setVisible (ui_->cbDopplerTracking->isChecked ());
|
||||
m_DopplerMethod=settings_->value("DopplerMethod",0).toInt();
|
||||
if(m_DopplerMethod==0) ui_->rbNoDoppler->setChecked(true);
|
||||
if(m_DopplerMethod==1) ui_->rbFullTrack->setChecked(true);
|
||||
if(m_DopplerMethod==2) ui_->rbConstFreqOnMoon->setChecked(true);
|
||||
m_stepHz=settings_->value("StepHz",1).toInt();
|
||||
if(m_stepHz==1) ui_->rb1Hz->setChecked(true);
|
||||
if(m_stepHz==10) ui_->rb10Hz->setChecked(true);
|
||||
if(m_stepHz==100) ui_->rb100Hz->setChecked(true);
|
||||
m_kHz=settings_->value("kHzAdd",100).toInt();
|
||||
ui_->kHzSpinBox->setValue(m_kHz);
|
||||
m_bRxAudioTrack=settings_->value("RxAudioTrack",false).toBool();
|
||||
m_bTxAudioTrack=settings_->value("TxAudioTrack",false).toBool();
|
||||
ui_->cbTxAudioTrack->setChecked(m_bTxAudioTrack);
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 0: ui_->rbNoDoppler->setChecked (true); break;
|
||||
case 1: ui_->rbFullTrack->setChecked (true); break;
|
||||
case 2: ui_->rbConstFreqOnMoon->setChecked (true); break;
|
||||
case 3: ui_->rbRxOnly->setChecked (true); break;
|
||||
}
|
||||
move (settings_->value ("window/pos", pos ()).toPoint ());
|
||||
}
|
||||
|
||||
void Astro::write_settings ()
|
||||
{
|
||||
SettingsGroup g (settings_, "Astro");
|
||||
settings_->setValue ("DopplerTracking", ui_->cbDopplerTracking->isChecked ());
|
||||
//settings_->setValue ("DopplerTracking", ui_->cbDopplerTracking->isChecked ());
|
||||
settings_->setValue ("DopplerMethod",m_DopplerMethod);
|
||||
settings_->setValue ("StepHz",m_stepHz);
|
||||
settings_->setValue ("kHzAdd",m_kHz);
|
||||
settings_->setValue ("RxAudioTrack",m_bRxAudioTrack);
|
||||
settings_->setValue ("TxAudioTrack",m_bTxAudioTrack);
|
||||
settings_->setValue ("window/pos", pos ());
|
||||
}
|
||||
|
||||
auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const& hisgrid, Frequency freq,
|
||||
bool dx_is_self, bool bTx) -> FrequencyDelta
|
||||
bool dx_is_self, bool bTx, bool no_tx_QSY, int TR_period) -> Correction
|
||||
{
|
||||
Frequency freq_moon {freq + 1000 * m_kHz + m_Hz};
|
||||
Frequency freq_moon {freq};
|
||||
double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx;
|
||||
double ramoon,decmoon,dgrd,poloffset,xnr,techo,width1,width2;
|
||||
int ntsky;
|
||||
@ -148,94 +145,125 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const
|
||||
}
|
||||
ui_->text_label->setText(message);
|
||||
|
||||
FrequencyDelta astro_correction {0};
|
||||
Correction correction;
|
||||
if (ui_->cbDopplerTracking->isChecked ()) {
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 1:
|
||||
// All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
if(dx_is_self) {
|
||||
astro_correction = m_stepHz*qRound(double(ndop00)/m_stepHz);
|
||||
} else {
|
||||
astro_correction = m_stepHz*qRound(double(ndop)/m_stepHz);
|
||||
}
|
||||
case 1: // All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
case 3: // Both stations do full correction on Rx and none on Tx
|
||||
correction.rx = dx_is_self ? ndop00 : ndop;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Doppler correction to constant frequency on Moon
|
||||
astro_correction = m_stepHz*qRound(double(ndop00/2.0)/m_stepHz);
|
||||
correction.rx = ndop00 / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bTx) {
|
||||
astro_correction = 1000 * m_kHz + m_Hz - astro_correction;
|
||||
} else {
|
||||
if(dx_is_self && m_DopplerMethod==1) {
|
||||
astro_correction = 1000*m_kHz + m_Hz;
|
||||
} else {
|
||||
astro_correction += 1000*m_kHz + m_Hz;
|
||||
if (3 != m_DopplerMethod) correction.tx = -correction.rx;
|
||||
if(dx_is_self && m_DopplerMethod == 1) correction.rx = 0;
|
||||
|
||||
if (no_tx_QSY && 3 != m_DopplerMethod && 0 != m_DopplerMethod)
|
||||
{
|
||||
// calculate a single correction for transmit half way through
|
||||
// the period as a compromise for rigs that can't CAT QSY
|
||||
// while transmitting
|
||||
//
|
||||
// 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 target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000);
|
||||
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()};
|
||||
int nhr {target_date_time.time().hour()};
|
||||
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.toLatin1().constData(),
|
||||
hisgrid.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon,
|
||||
&azmoondx, &elmoondx, &ntsky, &ndop, &ndop00, &ramoon, &decmoon,
|
||||
&dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx,
|
||||
"", jpleph.toLatin1().constData(), 6, 6,
|
||||
0, jpleph.length());
|
||||
FrequencyDelta offset {0};
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 1:
|
||||
// All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
offset = dx_is_self ? ndop00 : ndop;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Doppler correction to constant frequency on Moon
|
||||
offset = ndop00 / 2;
|
||||
break;
|
||||
}
|
||||
correction.tx = -offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
return astro_correction;
|
||||
return correction;
|
||||
}
|
||||
|
||||
void Astro::check_split ()
|
||||
{
|
||||
if (doppler_tracking () && !configuration_->split_mode ())
|
||||
{
|
||||
QMessageBox::warning (this, "Doppler Tracking",
|
||||
"Split operating is required for Doppler tracking");
|
||||
ui_->rbNoDoppler->click ();
|
||||
}
|
||||
}
|
||||
|
||||
void Astro::on_rbFullTrack_clicked()
|
||||
{
|
||||
m_DopplerMethod = 1;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbRxOnly_clicked()
|
||||
{
|
||||
m_DopplerMethod = 3;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbConstFreqOnMoon_clicked()
|
||||
{
|
||||
m_DopplerMethod = 2;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbNoDoppler_clicked()
|
||||
{
|
||||
m_DopplerMethod = 0;
|
||||
}
|
||||
|
||||
void Astro::on_rb1Hz_clicked()
|
||||
{
|
||||
m_stepHz=1;
|
||||
}
|
||||
|
||||
void Astro::on_rb10Hz_clicked()
|
||||
{
|
||||
m_stepHz=10;
|
||||
}
|
||||
|
||||
void Astro::on_rb100Hz_clicked()
|
||||
{
|
||||
m_stepHz=100;
|
||||
}
|
||||
|
||||
void Astro::on_cbTxAudioTrack_toggled(bool b)
|
||||
{
|
||||
m_bTxAudioTrack=b;
|
||||
}
|
||||
|
||||
void Astro::on_kHzSpinBox_valueChanged(int n)
|
||||
{
|
||||
m_kHz=n;
|
||||
}
|
||||
|
||||
void Astro::on_HzSpinBox_valueChanged(int n)
|
||||
{
|
||||
m_Hz=n;
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
bool Astro::doppler_tracking () const
|
||||
{
|
||||
return ui_->cbDopplerTracking->isChecked ();
|
||||
return ui_->cbDopplerTracking->isChecked () && m_DopplerMethod;
|
||||
}
|
||||
|
||||
bool Astro::trackVFO()
|
||||
void Astro::on_cbDopplerTracking_toggled(bool)
|
||||
{
|
||||
return m_bTrackVFO;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_cbTrackVFO_toggled(bool b)
|
||||
void Astro::nominal_frequency (Frequency rx, Frequency tx)
|
||||
{
|
||||
m_bTrackVFO=b;
|
||||
ui_->sked_frequency_label->setText (Radio::pretty_frequency_MHz_string (rx));
|
||||
ui_->sked_tx_frequency_label->setText (Radio::pretty_frequency_MHz_string (tx));
|
||||
}
|
||||
|
||||
void Astro::hideEvent (QHideEvent * e)
|
||||
{
|
||||
Q_EMIT tracking_update ();
|
||||
QWidget::hideEvent (e);
|
||||
}
|
||||
|
71
astro.h
71
astro.h
@ -2,7 +2,8 @@
|
||||
#ifndef ASTRO_H
|
||||
#define ASTRO_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QDialog>
|
||||
|
||||
#include "Radio.hpp"
|
||||
|
||||
class QSettings;
|
||||
@ -12,63 +13,75 @@ namespace Ui {
|
||||
}
|
||||
|
||||
class Astro final
|
||||
: public QWidget
|
||||
: public QDialog
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
using Frequency = Radio::Frequency;
|
||||
using FrequencyDelta = Radio::FrequencyDelta;
|
||||
|
||||
public:
|
||||
explicit Astro(QSettings * settings, Configuration const *, QWidget * parent = nullptr);
|
||||
~Astro ();
|
||||
FrequencyDelta astroUpdate(QDateTime const& t, QString const& mygrid, QString const& hisgrid, Frequency frequency,
|
||||
bool dx_is_self, bool bTx);
|
||||
|
||||
struct Correction
|
||||
{
|
||||
Correction ()
|
||||
: rx {0}
|
||||
, tx {0}
|
||||
{}
|
||||
Correction (Correction const&) = default;
|
||||
Correction& operator = (Correction const&) = default;
|
||||
|
||||
FrequencyDelta rx;
|
||||
FrequencyDelta tx;
|
||||
};
|
||||
Correction astroUpdate(QDateTime const& t,
|
||||
QString const& mygrid,
|
||||
QString const& hisgrid,
|
||||
Frequency frequency,
|
||||
bool dx_is_self,
|
||||
bool bTx,
|
||||
bool no_tx_QSY,
|
||||
int TR_period);
|
||||
|
||||
bool doppler_tracking () const;
|
||||
bool trackVFO();
|
||||
Q_SIGNAL void doppler_tracking_toggled (bool);
|
||||
Q_SLOT void nominal_frequency (Frequency rx, Frequency tx);
|
||||
Q_SIGNAL void tracking_update () const;
|
||||
|
||||
protected:
|
||||
void hideEvent (QHideEvent *) override;
|
||||
void closeEvent (QCloseEvent *) override;
|
||||
|
||||
private slots:
|
||||
void on_rbConstFreqOnMoon_clicked();
|
||||
void on_rbFullTrack_clicked();
|
||||
void on_rbRxOnly_clicked();
|
||||
void on_rbNoDoppler_clicked();
|
||||
void on_rb1Hz_clicked();
|
||||
void on_rb10Hz_clicked();
|
||||
void on_rb100Hz_clicked();
|
||||
void on_cbTxAudioTrack_toggled(bool b);
|
||||
void on_kHzSpinBox_valueChanged(int n);
|
||||
void on_HzSpinBox_valueChanged(int n);
|
||||
void on_cbTrackVFO_toggled(bool b);
|
||||
void on_cbDopplerTracking_toggled(bool);
|
||||
|
||||
private:
|
||||
void read_settings ();
|
||||
void write_settings ();
|
||||
void check_split ();
|
||||
|
||||
QSettings * settings_;
|
||||
Configuration const * configuration_;
|
||||
Ui::Astro * ui_;
|
||||
bool m_bRxAudioTrack;
|
||||
bool m_bTxAudioTrack;
|
||||
bool m_bTrackVFO;
|
||||
|
||||
qint32 m_DopplerMethod;
|
||||
qint32 m_kHz;
|
||||
qint32 m_Hz;
|
||||
qint32 m_stepHz;
|
||||
};
|
||||
|
||||
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,
|
||||
int len1, int len2, int len3, int len4);
|
||||
inline
|
||||
bool operator == (Astro::Correction const& lhs, Astro::Correction const& rhs)
|
||||
{
|
||||
return lhs.rx == rhs.rx && lhs.tx == rhs.tx;
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator != (Astro::Correction const& lhs, Astro::Correction const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
#endif // ASTRO_H
|
||||
|
489
astro.ui
489
astro.ui
@ -1,243 +1,246 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Astro</class>
|
||||
<widget class="QWidget" name="Astro">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>440</width>
|
||||
<height>406</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QWidget" name="doppler_widget" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">* {
|
||||
font-weight: normal;
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Frequency above nominal band edge</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="kHzSpinBox">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> kHz</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>200</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="HzSpinBox">
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> Hz</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-2000</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>2000</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>100</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Doppler tracking</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbFullTrack">
|
||||
<property name="text">
|
||||
<string>Full Doppler to DX Grid</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbConstFreqOnMoon">
|
||||
<property name="text">
|
||||
<string>Constant frequency on Moon</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbNoDoppler">
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Transceiver step size</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb1Hz">
|
||||
<property name="text">
|
||||
<string>1 Hz</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb10Hz">
|
||||
<property name="text">
|
||||
<string>10 Hz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rb100Hz">
|
||||
<property name="text">
|
||||
<string>100 Hz</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Enable</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbTrackVFO">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Track VFOs</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbTxAudioTrack">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Track Tx audio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="text_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">* {
|
||||
font-family: Courier;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Astro Data</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbDopplerTracking">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Doppler tracking</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Astro</class>
|
||||
<widget class="QWidget" name="Astro">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>359</width>
|
||||
<height>287</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QWidget" name="doppler_widget" native="true">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">* {
|
||||
font-weight: normal;
|
||||
}</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Doppler tracking</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbFullTrack">
|
||||
<property name="toolTip">
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Full Doppler to DX Grid</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbRxOnly">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Both stations do full correction to their QSO partner's grid square during receive, no correction is applied on transmit.</p><p>This mode facilitates accurate Doppler shift correction when one or both stations have a rig that does not accept CAT QSY commands while transmitting.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Receive only</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbConstFreqOnMoon">
|
||||
<property name="toolTip">
|
||||
<string><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></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Constant frequency on Moon</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbNoDoppler">
|
||||
<property name="toolTip">
|
||||
<string><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></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>None</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Sked frequency</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="sked_tx_frequency_label">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">* {
|
||||
font-family: Courier;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="sked_frequency_label">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">* {
|
||||
font-family: Courier;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>0</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">* {
|
||||
font-family: Courier;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rx:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="styleSheet">
|
||||
<string notr="true">* {
|
||||
font-family: Courier;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Tx:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Press and hold the CTRL key to adjust the sked frequency manually with the rig's VFO dial or enter directly into the band edit.</p></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::AutoText</enum>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="text_label">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="styleSheet">
|
||||
<string notr="true">* {
|
||||
font-family: Courier;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}</string>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Astro Data</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbDopplerTracking">
|
||||
<property name="styleSheet">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Doppler tracking</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
551
mainwindow.cpp
551
mainwindow.cpp
File diff suppressed because it is too large
Load Diff
31
mainwindow.h
31
mainwindow.h
@ -30,6 +30,7 @@
|
||||
#include "logbook/logbook.h"
|
||||
#include "decodedtext.h"
|
||||
#include "commons.h"
|
||||
#include "astro.h"
|
||||
|
||||
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
|
||||
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
|
||||
@ -59,7 +60,6 @@ class FastGraph;
|
||||
class WideGraph;
|
||||
class LogQSO;
|
||||
class Transceiver;
|
||||
class Astro;
|
||||
class MessageAveraging;
|
||||
class MessageClient;
|
||||
class QTime;
|
||||
@ -78,6 +78,7 @@ class MainWindow : public QMainWindow
|
||||
|
||||
public:
|
||||
using Frequency = Radio::Frequency;
|
||||
using FrequencyDelta = Radio::FrequencyDelta;
|
||||
using Mode = Modes::Mode;
|
||||
|
||||
// Multiple instances: call MainWindow() with *thekey
|
||||
@ -103,7 +104,7 @@ public slots:
|
||||
void p1ReadFromStdout();
|
||||
void p1ReadFromStderr();
|
||||
void p1Error(QProcess::ProcessError);
|
||||
void setXIT(int n);
|
||||
void setXIT(int n, Frequency base = 0u);
|
||||
void setFreq4(int rxFreq, int txFreq);
|
||||
void msgAvgDecode2();
|
||||
void fastPick(int x0, int x1, int y);
|
||||
@ -199,9 +200,9 @@ private slots:
|
||||
void on_cbTxLock_clicked(bool checked);
|
||||
void on_outAttenuation_valueChanged (int);
|
||||
void rigOpen ();
|
||||
void handle_transceiver_update (Transceiver::TransceiverState);
|
||||
void handle_transceiver_failure (QString reason);
|
||||
void on_actionAstronomical_data_triggered();
|
||||
void handle_transceiver_update (Transceiver::TransceiverState const&);
|
||||
void handle_transceiver_failure (QString const& reason);
|
||||
void on_actionAstronomical_data_toggled (bool);
|
||||
void on_actionShort_list_of_add_on_prefixes_and_suffixes_triggered();
|
||||
void getpfx();
|
||||
void band_changed (Frequency);
|
||||
@ -238,7 +239,6 @@ private slots:
|
||||
void on_pbTxNext_clicked(bool b);
|
||||
void on_actionEcho_Graph_triggered();
|
||||
void on_actionEcho_triggered();
|
||||
void DopplerTracking_toggled (bool);
|
||||
void on_actionISCAT_triggered();
|
||||
void on_actionFast_Graph_triggered();
|
||||
void fast_decode_done();
|
||||
@ -274,6 +274,8 @@ private:
|
||||
Q_SIGNAL void toggleShorthand () const;
|
||||
|
||||
private:
|
||||
void astroUpdate ();
|
||||
|
||||
QDir m_dataDir;
|
||||
QString m_revision;
|
||||
bool m_multiple;
|
||||
@ -298,9 +300,11 @@ private:
|
||||
QScopedPointer<HelpTextWindow> m_mouseCmnds;
|
||||
QScopedPointer<MessageAveraging> m_msgAvgWidget;
|
||||
|
||||
Frequency m_dialFreq;
|
||||
Frequency m_dialFreq0;
|
||||
Frequency m_dialFreqRxWSPR;
|
||||
Transceiver::TransceiverState m_rigState;
|
||||
Frequency m_lastDialFreq;
|
||||
QString m_lastBand;
|
||||
Frequency m_callingFrequency;
|
||||
Frequency m_dialFreqRxWSPR; // best guess at WSPR QRG
|
||||
|
||||
Detector * m_detector;
|
||||
SoundInput * m_soundInput;
|
||||
@ -311,9 +315,9 @@ private:
|
||||
qint64 m_msErase;
|
||||
qint64 m_secBandChanged;
|
||||
qint64 m_freqMoon;
|
||||
qint64 m_freqNominal;
|
||||
qint64 m_dialFreqTx;
|
||||
qint64 m_dialFreqRx;
|
||||
Frequency m_freqNominal;
|
||||
Frequency m_freqTxNominal;
|
||||
Astro::Correction m_astroCorrection;
|
||||
|
||||
double m_s6;
|
||||
double m_tRemaining;
|
||||
@ -536,7 +540,6 @@ private:
|
||||
void msgtype(QString t, QLineEdit* tx);
|
||||
void stub();
|
||||
void statusChanged();
|
||||
void qsy(Frequency f);
|
||||
bool gridOK(QString g);
|
||||
bool shortList(QString callsign);
|
||||
void transmit (double snr = 99.);
|
||||
@ -552,7 +555,7 @@ private:
|
||||
void enable_DXCC_entity (bool on);
|
||||
void switch_mode (Mode);
|
||||
void WSPR_scheduling ();
|
||||
void astroCalculations (QDateTime const&, bool adjust);
|
||||
void setRig ();
|
||||
void WSPR_history(Frequency dialFreq, int ndecodes);
|
||||
QString WSPR_hhmm(int n);
|
||||
void fast_config(bool b);
|
||||
|
5803
mainwindow.ui
5803
mainwindow.ui
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user