From 884490af0325f8f64626953eb129f58c15d75a62 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Fri, 17 Oct 2014 10:07:45 +0000 Subject: [PATCH] Support for the Yaesu FTdx3000 and similar rigs via HRD There is an outstanding issue with the FTdx3000 via HRD in that setting the "other" VFO mode doesn't work. This appears to be insoluable and the only current option is to set "Mode" to "None" in WSJT-X leaving mode setting to the user. As it happens the best mode combo on this rig is probably DATA-U on Tx and USB on Rx which would require "Mode" as "None" anyway. This change is quite large including several general strategy changes in an attempt to make the HRD interface more generic and more robust. Also cleaned up trace output removing stuff that is working and just clutters output. Merged from wsjtx-1.4 branch. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@4524 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- HRDTransceiver.cpp | 346 +++++++++++++++++++++++++++++++++++---------- HRDTransceiver.hpp | 15 +- 2 files changed, 282 insertions(+), 79 deletions(-) diff --git a/HRDTransceiver.cpp b/HRDTransceiver.cpp index 7c91adf0c..c559a56d5 100644 --- a/HRDTransceiver.cpp +++ b/HRDTransceiver.cpp @@ -90,6 +90,9 @@ HRDTransceiver::HRDTransceiver (std::unique_ptr wrapped , split_off_button_ {-1} , tx_A_button_ {-1} , tx_B_button_ {-1} + , rx_A_button_ {-1} + , rx_B_button_ {-1} + , receiver_dropdown_ {-1} , ptt_button_ {-1} , reversed_ {false} { @@ -253,11 +256,19 @@ void HRDTransceiver::do_start () sliders_[s] = range; } + // set RX VFO + rx_A_button_ = find_button (QRegExp ("^(RX~A)$")); + rx_B_button_ = find_button (QRegExp ("^(RX~B)$")); + + // select VFO (sometime set as well) vfo_A_button_ = find_button (QRegExp ("^(VFO~A|Main)$")); vfo_B_button_ = find_button (QRegExp ("^(VFO~B|Sub)$")); + vfo_toggle_button_ = find_button (QRegExp ("^(A~/~B)$")); + + // check we have a way of addressing both VFOs Q_ASSERT (vfo_toggle_button_ >= 0 || (vfo_A_button_ >= 0 && vfo_B_button_ >=0)); - + split_mode_button_ = find_button (QRegExp ("^(Spl~On|Spl_On|Split)$")); split_off_button_ = find_button (QRegExp ("^(Spl~Off|Spl_Off)$")); @@ -266,9 +277,14 @@ void HRDTransceiver::do_start () split_mode_dropdown_selection_on_ = find_dropdown_selection (split_mode_dropdown_, QRegExp ("^(On)$")); split_mode_dropdown_selection_off_ = find_dropdown_selection (split_mode_dropdown_, QRegExp ("^(Off)$")); } + else if ((receiver_dropdown_ = find_dropdown (QRegExp ("^Receiver$"))) >= 0) + { + rx_A_selection_ = find_dropdown_selection (receiver_dropdown_, QRegExp ("^(RX / Off)$")); + rx_B_selection_ = find_dropdown_selection (receiver_dropdown_, QRegExp ("^(Mute / RX)$")); + } - tx_A_button_ = find_button (QRegExp ("^(TX~main|TX~-~A)$")); - tx_B_button_ = find_button (QRegExp ("^(TX~sub|TX~-~B)$")); + tx_A_button_ = find_button (QRegExp ("^(TX~main|TX~-~A|TX~A)$")); + tx_B_button_ = find_button (QRegExp ("^(TX~sub|TX~-~B|TX~B)$")); Q_ASSERT (split_mode_button_ >= 0 || split_mode_dropdown_ >= 0 || (tx_A_button_ >= 0 && tx_B_button_ >= 0)); @@ -276,6 +292,10 @@ void HRDTransceiver::do_start () { map_modes (mode_A_dropdown_, &mode_A_map_); } + else + { + Q_ASSERT (mode_A_dropdown_ <= 0); + } if ((mode_B_dropdown_ = find_dropdown (QRegExp ("^(Sub Mode)$"))) >= 0) { @@ -284,31 +304,10 @@ void HRDTransceiver::do_start () ptt_button_ = find_button (QRegExp ("^(TX)$")); - sync_impl (); -} - -void HRDTransceiver::do_stop () -{ - if (hrd_) - { - hrd_->close (); - } - - if (wrapped_) - { - wrapped_->stop (); - } - -#if WSJT_TRACE_CAT - qDebug () << "HRDTransceiver::stop: state:" << state () << "reversed =" << reversed_; -#endif -} - -void HRDTransceiver::sync_impl () -{ if (vfo_count_ == 1 && ((vfo_B_button_ >= 0 && vfo_A_button_ >= 0) || vfo_toggle_button_ >= 0)) { - // put the rig into a known state + // put the rig into a known state for tricky cases like Icoms + auto f = send_command ("get frequency").toUInt (); auto m = lookup_mode (get_dropdown (mode_A_dropdown_), mode_A_map_); set_button (vfo_B_button_ >= 0 ? vfo_B_button_ : vfo_toggle_button_); @@ -328,8 +327,23 @@ void HRDTransceiver::sync_impl () update_mode (lookup_mode (get_dropdown (mode_A_dropdown_), mode_A_map_)); } } +} - poll (); +void HRDTransceiver::do_stop () +{ + if (hrd_) + { + hrd_->close (); + } + + if (wrapped_) + { + wrapped_->stop (); + } + +#if WSJT_TRACE_CAT + qDebug () << "HRDTransceiver::stop: state:" << state () << "reversed =" << reversed_; +#endif } int HRDTransceiver::find_button (QRegExp const& re) const @@ -367,12 +381,12 @@ void HRDTransceiver::map_modes (int dropdown, ModeMap *map) map->push_back (std::forward_as_tuple (CW_R, find_dropdown_selection (dropdown, QRegExp ("^(CW-R|CW)$")))); map->push_back (std::forward_as_tuple (LSB, find_dropdown_selection (dropdown, QRegExp ("^(LSB)$")))); map->push_back (std::forward_as_tuple (USB, find_dropdown_selection (dropdown, QRegExp ("^(USB)$")))); - map->push_back (std::forward_as_tuple (DIG_U, find_dropdown_selection (dropdown, QRegExp ("^(DIG|PKT-U|USB)$")))); - map->push_back (std::forward_as_tuple (DIG_L, find_dropdown_selection (dropdown, QRegExp ("^(DIG|PKT-L|LSB)$")))); - map->push_back (std::forward_as_tuple (FSK, find_dropdown_selection (dropdown, QRegExp ("^(DIG|FSK|RTTY)$")))); - map->push_back (std::forward_as_tuple (FSK_R, find_dropdown_selection (dropdown, QRegExp ("^(DIG|FSK-R|RTTY-R|RTTY)$")))); + map->push_back (std::forward_as_tuple (DIG_U, find_dropdown_selection (dropdown, QRegExp ("^(DIG|DATA-U|PKT-U|USB)$")))); + map->push_back (std::forward_as_tuple (DIG_L, find_dropdown_selection (dropdown, QRegExp ("^(DIG|DATA-L|PKT-L|LSB)$")))); + map->push_back (std::forward_as_tuple (FSK, find_dropdown_selection (dropdown, QRegExp ("^(DIG|FSK|RTTY|RTTY-LSB)$")))); + map->push_back (std::forward_as_tuple (FSK_R, find_dropdown_selection (dropdown, QRegExp ("^(DIG|FSK-R|RTTY-R|RTTY|RTTY-USB)$")))); map->push_back (std::forward_as_tuple (AM, find_dropdown_selection (dropdown, QRegExp ("^(AM)$")))); - map->push_back (std::forward_as_tuple (FM, find_dropdown_selection (dropdown, QRegExp ("^(FM|FM\\(N\\)|WFM)$")))); + map->push_back (std::forward_as_tuple (FM, find_dropdown_selection (dropdown, QRegExp ("^(FM|FM\\(N\\)|FM-N|WFM)$")))); map->push_back (std::forward_as_tuple (DIG_FM, find_dropdown_selection (dropdown, QRegExp ("^(PKT-FM|PKT|FM)$")))); #if WSJT_TRACE_CAT @@ -440,7 +454,7 @@ void HRDTransceiver::set_dropdown (int dd, int value) auto dd_name = dropdown_names_.value (dd); if (value >= 0) { - send_simple_command ("set dropdown " + dd_name.replace (' ', '~') + ' ' + dropdowns_.value (dd_name).value (value) + ' ' + QString::number (value)); + send_simple_command ("set dropdown " + dd_name.replace (' ', '~') + ' ' + dropdowns_.value (dd_name).value (value).replace (' ', '~') + ' ' + QString::number (value)); } else { @@ -465,8 +479,8 @@ void HRDTransceiver::do_ptt (bool on) set_button (ptt_button_, on); } // else - // allow for pathological HRD rig interfaces that don't do - // PTT by simply not even trying + // allow for pathological HRD rig interfaces that don't do + // PTT by simply not even trying } else { @@ -497,25 +511,85 @@ void HRDTransceiver::do_frequency (Frequency f) qDebug () << "HRDTransceiver::do_frequency:" << f << "reversed:" << reversed_; #endif - send_simple_command ("set frequency-hz " + QString::number (f)); + auto fo_string = QString::number (f); + if (vfo_count_ > 1 && reversed_) + { + auto frequencies = send_command ("get frequencies").trimmed ().split ('-', QString::SkipEmptyParts); + send_simple_command ("set frequencies-hz " + QString::number (frequencies[0].toUInt ()) + ' ' + fo_string); + } + else + { + send_simple_command ("set frequency-hz " + QString::number (f)); + } update_rx_frequency (f); } void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode) { #if WSJT_TRACE_CAT - qDebug () << "HRDTransceiver::do_tx_frequency:" << tx << "reversed:" << reversed_; + qDebug () << "HRDTransceiver::do_tx_frequency:" << tx << "rationalize mode:" << rationalise_mode << "reversed:" << reversed_; #endif - bool split {tx != 0}; - - if (vfo_count_ > 1 && vfo_B_button_ >= 0) + // re-check if reversed VFOs + bool rx_A {true}; + bool rx_B {false}; + if (receiver_dropdown_ >= 0) { - reversed_ = is_button_checked (vfo_B_button_); + auto selection = get_dropdown (receiver_dropdown_); + rx_A = selection == rx_A_selection_.front (); + if (!rx_A) + { + rx_B = selection == rx_B_selection_.front (); + } } + else if (vfo_B_button_ >= 0 || rx_B_button_ >= 0) + { + rx_A = is_button_checked (rx_A_button_ >= 0 ? rx_A_button_ : vfo_A_button_); + if (!rx_A) + { + rx_B = is_button_checked (rx_B_button_ >= 0 ? rx_B_button_ : vfo_B_button_); + } + } + reversed_ = rx_B; + bool split {tx != 0}; if (split) { + if (rationalise_mode) + { + if (!reversed_ && mode_B_dropdown_ >= 0) + { + set_dropdown (mode_B_dropdown_, lookup_mode (state ().mode (), mode_B_map_)); + } + else if (reversed_ && mode_B_dropdown_ >= 0) + { + set_dropdown (mode_A_dropdown_, lookup_mode (state ().mode (), mode_A_map_)); + } + else + { + Q_ASSERT (mode_A_dropdown_ >= 0 && ((vfo_A_button_ >=0 && vfo_B_button_ >=0) || vfo_toggle_button_ >= 0)); + + if (rx_B_button_ >= 0) + { + set_button (reversed_ ? rx_A_button_ : rx_B_button_); + set_dropdown (mode_A_dropdown_, lookup_mode (state ().mode (), mode_A_map_)); + set_button (reversed_ ? rx_B_button_ : rx_A_button_); + } + else if (receiver_dropdown_ >= 0) + { + set_dropdown (receiver_dropdown_, (reversed_ ? rx_A_selection_ : rx_B_selection_).front ()); + 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 + { + 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_); + } + } + } + auto fo_string = QString::number (tx); if (reversed_) { @@ -533,20 +607,19 @@ void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode) } else if ((vfo_B_button_ >= 0 && vfo_A_button_ >= 0) || vfo_toggle_button_ >= 0) { - // we rationalise the modes and VFOs here as well as the frequencies + // 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 || mode_A_dropdown_ >= 0)) + if (rationalise_mode && mode_B_dropdown_ < 0) { - set_dropdown (mode_B_dropdown_ >= 0 ? mode_B_dropdown_ : mode_A_dropdown_, lookup_mode (state ().mode (), mode_B_dropdown_ >= 0 ? mode_B_map_ : mode_A_map_)); + // 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_); } } - if (rationalise_mode && (mode_B_dropdown_ >= 0 || mode_A_dropdown_ >= 0)) - { - set_dropdown (mode_B_dropdown_ >= 0 ? mode_B_dropdown_ : mode_A_dropdown_, lookup_mode (state ().mode (), mode_B_dropdown_ >= 0 ? mode_B_map_ : mode_A_map_)); - } } update_other_frequency (tx); @@ -571,6 +644,18 @@ void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode) { if (reversed_ != is_button_checked (tx_A_button_)) { + if (rx_A_button_ >= 0 && rx_B_button_ >= 0) + { + set_button (reversed_ ? rx_B_button_ : rx_A_button_); + } + else if (receiver_dropdown_ >= 0) + { + set_dropdown (receiver_dropdown_, (reversed_ ? rx_B_selection_ : rx_A_selection_).front ()); + } + else + { + set_button (reversed_ ? vfo_B_button_ : vfo_A_button_); + } set_button (reversed_ ? tx_A_button_ : tx_B_button_); } } @@ -578,6 +663,18 @@ void HRDTransceiver::do_tx_frequency (Frequency tx, bool rationalise_mode) { if (reversed_ != is_button_checked (tx_B_button_)) { + if (rx_A_button_ >= 0 && rx_B_button_ >= 0) + { + set_button (reversed_ ? rx_B_button_ : rx_A_button_); + } + else if (receiver_dropdown_ >= 0) + { + set_dropdown (receiver_dropdown_, (reversed_ ? rx_B_selection_ : rx_A_selection_).front ()); + } + else + { + set_button (reversed_ ? vfo_B_button_ : vfo_A_button_); + } set_button (reversed_ ? tx_B_button_ : tx_A_button_); } } @@ -591,22 +688,84 @@ void HRDTransceiver::do_mode (MODE mode, bool rationalise) qDebug () << "HRDTransceiver::do_mode:" << mode; #endif - if (mode_A_dropdown_ >= 0) + if (reversed_ && mode_B_dropdown_ >= 0) + { + set_dropdown (mode_B_dropdown_, lookup_mode (mode, mode_B_map_)); + } + else { set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_)); } if (rationalise && state ().split ()) // rationalise mode if split { - if (mode_B_dropdown_ >= 0) + if (reversed_) { - set_dropdown (mode_B_dropdown_, lookup_mode (mode, mode_B_map_)); + if (mode_B_dropdown_ >= 0) + { + set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_)); + } + else + { + Q_ASSERT ((vfo_B_button_ >= 0 && vfo_A_button_ >= 0) || vfo_toggle_button_ >= 0); + + if (rx_B_button_ >= 0) + { + set_button (rx_A_button_); + set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_)); + set_button (rx_B_button_); + } + else if (receiver_dropdown_ >= 0) + { + set_dropdown (receiver_dropdown_, rx_A_selection_.front ()); + set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_)); + set_dropdown (receiver_dropdown_, rx_B_selection_.front ()); + } + else + { + 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_); + } + if ( tx_A_button_ >= 0) + { + set_button (tx_A_button_); + } + } } - else if (vfo_count_ < 2 && ((vfo_B_button_ >= 0 && vfo_A_button_ >= 0) || vfo_toggle_button_ >= 0) && (mode_B_dropdown_ >= 0 || mode_A_dropdown_ >= 0)) + else { - set_button (vfo_B_button_ >= 0 ? vfo_B_button_ : vfo_toggle_button_); - set_dropdown (mode_B_dropdown_ >= 0 ? mode_B_dropdown_ : mode_A_dropdown_, lookup_mode (mode, mode_B_dropdown_ >= 0 ? mode_B_map_ : mode_A_map_)); - set_button (vfo_A_button_ >= 0 ? vfo_A_button_ : vfo_toggle_button_); + if (mode_B_dropdown_ >= 0) + { + set_dropdown (mode_B_dropdown_, lookup_mode (mode, mode_B_map_)); + } + else + { + Q_ASSERT ((vfo_B_button_ >= 0 && vfo_A_button_ >= 0) || vfo_toggle_button_ >= 0); + + if (rx_B_button_ >= 0) + { + set_button (rx_B_button_); + set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_)); + set_button (rx_A_button_); + } + else if (receiver_dropdown_ >= 0) + { + set_dropdown (receiver_dropdown_, rx_B_selection_.front ()); + set_dropdown (mode_A_dropdown_, lookup_mode (mode, mode_A_map_)); + set_dropdown (receiver_dropdown_, rx_A_selection_.front ()); + } + else + { + 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_); + } + if ( tx_B_button_ >= 0) + { + set_button (tx_B_button_); + } + } } } @@ -615,6 +774,11 @@ void HRDTransceiver::do_mode (MODE mode, bool rationalise) bool HRDTransceiver::is_button_checked (int button_index, bool no_debug) { + if (button_index < 0) + { + return false; + } + auto reply = send_command ("get button-select " + buttons_.value (button_index), no_debug); if ("1" != reply && "0" != reply) { @@ -631,6 +795,28 @@ void HRDTransceiver::poll () { #if WSJT_TRACE_CAT && WSJT_TRACE_CAT_POLLS bool quiet {false}; + + qDebug () << "+++++++ poll dump +++++++"; + qDebug () << "reversed:" << reversed_; + is_button_checked (vfo_A_button_); + is_button_checked (vfo_B_button_); + is_button_checked (vfo_toggle_button_); + is_button_checked (split_mode_button_); + is_button_checked (split_off_button_); + is_button_checked (rx_A_button_); + is_button_checked (rx_B_button_); + get_dropdown (receiver_dropdown_); + is_button_checked (tx_A_button_); + is_button_checked (tx_B_button_); + is_button_checked (ptt_button_); + get_dropdown (mode_A_dropdown_); + get_dropdown (mode_B_dropdown_); + if (!split_mode_dropdown_write_only_) + { + get_dropdown (split_mode_dropdown_); + } + qDebug () << "------- poll dump -------"; + #else bool quiet {true}; #endif @@ -662,11 +848,34 @@ void HRDTransceiver::poll () } else if (vfo_A_button_ >= 0 && vfo_B_button_ >= 0 && tx_A_button_ >= 0 && tx_B_button_ >= 0) { - auto vfo_A = is_button_checked (vfo_A_button_, quiet); + bool rx_A {true}; // no Rx taken as not reversed + bool rx_B {false}; + auto tx_A = is_button_checked (tx_A_button_, quiet); - update_split (vfo_A != tx_A); - reversed_ = !vfo_A; + // some rigs have dual Rx, we take VFO A/MAIN receiving as + // normal and only say reversed when only VFO B/SUB is active + // i.e. VFO A/MAIN muted VFO B/SUB active + if (receiver_dropdown_ >= 0) + { + auto selection = get_dropdown (receiver_dropdown_); + rx_A = selection == rx_A_selection_.front (); + if (!rx_A) + { + rx_B = selection == rx_B_selection_.front (); + } + } + else if (vfo_B_button_ >= 0 || rx_B_button_ >= 0) + { + rx_A = is_button_checked (rx_A_button_ >= 0 ? rx_A_button_ : vfo_A_button_, quiet); + if (!rx_A) + { + rx_B = is_button_checked (rx_B_button_ >= 0 ? rx_B_button_ : vfo_B_button_, quiet); + } + } + + update_split (rx_B == tx_A); + reversed_ = rx_B; } if (vfo_count_ > 1) @@ -680,10 +889,7 @@ void HRDTransceiver::poll () update_rx_frequency (send_command ("get frequency", quiet).toUInt ()); } - if (mode_A_dropdown_ >= 0) - { - update_mode (lookup_mode (get_dropdown (mode_A_dropdown_, quiet), mode_A_map_)); - } + update_mode (lookup_mode (get_dropdown (mode_A_dropdown_, quiet), mode_A_map_)); } QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool prepend_context, bool recurse) @@ -701,7 +907,7 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr if (!recurse && prepend_context) { - auto radio_name = send_command ("get radio", no_debug, current_radio_, true); + auto radio_name = send_command ("get radio", true, current_radio_, true); auto radio_iter = std::find_if (radios_.begin (), radios_.end (), [this, &radio_name] (RadioMap::value_type const& radio) { return std::get<1> (radio) == radio_name; @@ -736,14 +942,6 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr }; } - - if (!no_debug) - { -#if WSJT_TRACE_CAT - qDebug () << "HRDTransceiver::send_command:" << cmd; -#endif - } - if (v4 == protocol_) { auto message = ((prepend_context ? context + cmd : cmd) + "\r").toLocal8Bit (); @@ -810,12 +1008,6 @@ QString HRDTransceiver::send_command (QString const& cmd, bool no_debug, bool pr } QByteArray buffer (hrd_->readAll ()); - if (!no_debug) - { -#if WSJT_TRACE_CAT - qDebug () << "HRDTransceiver::send_command: reply byte count:" << buffer.size (); -#endif - } if (v4 == protocol_) { diff --git a/HRDTransceiver.hpp b/HRDTransceiver.hpp index 17e546b56..0b64d115e 100644 --- a/HRDTransceiver.hpp +++ b/HRDTransceiver.hpp @@ -54,7 +54,6 @@ private: QString send_command (QString const&, bool no_debug = false, bool prepend_context = true, bool recurse = false); void send_simple_command (QString const&, bool no_debug = false); bool write_to_port (char const *, qint64 length); - void sync_impl (); int find_button (QRegExp const&) const; int find_dropdown (QRegExp const&) const; std::vector find_dropdown_selection (int dropdown, QRegExp const&) const; @@ -92,7 +91,7 @@ private: using RadioMap = std::vector >; - RadioMap radios_; // Dictionary of available radios. + RadioMap radios_; // Dictionary of available radios. unsigned current_radio_; // The current addressed radio. @@ -162,6 +161,18 @@ private: int tx_B_button_; // The button to transmit on VFO B. + int rx_A_button_; // The button to receive on VFO A + // A. May be -1 if none available. + + int rx_B_button_; // The button to receive on VFO B + // May be -1 if none available. + + int receiver_dropdown_; // Select receiver + + std::vector rx_A_selection_; + + std::vector rx_B_selection_; + int ptt_button_; // The button to toggle PTT. bool reversed_; // True if VFOs are reversed.