// // Copyright 2018 Ettus Research, a National Instruments Company // Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // #include "rhodium_constants.hpp" #include "rhodium_cpld_ctrl.hpp" #include "rhodium_radio_control.hpp" #include using namespace uhd; using namespace uhd::usrp; using namespace uhd::rfnoc; namespace { const char* rx_band_to_log(rhodium_radio_control_impl::rx_band rx_band) { switch (rx_band) { case rhodium_radio_control_impl::rx_band::RX_BAND_0: return "0"; case rhodium_radio_control_impl::rx_band::RX_BAND_1: return "1"; case rhodium_radio_control_impl::rx_band::RX_BAND_2: return "2"; case rhodium_radio_control_impl::rx_band::RX_BAND_3: return "3"; case rhodium_radio_control_impl::rx_band::RX_BAND_4: return "4"; case rhodium_radio_control_impl::rx_band::RX_BAND_5: return "5"; case rhodium_radio_control_impl::rx_band::RX_BAND_6: return "6"; case rhodium_radio_control_impl::rx_band::RX_BAND_7: return "7"; case rhodium_radio_control_impl::rx_band::RX_BAND_INVALID: return "INVALID"; default: UHD_THROW_INVALID_CODE_PATH(); } } const char* tx_band_to_log(rhodium_radio_control_impl::tx_band tx_band) { switch (tx_band) { case rhodium_radio_control_impl::tx_band::TX_BAND_0: return "0"; case rhodium_radio_control_impl::tx_band::TX_BAND_1: return "1"; case rhodium_radio_control_impl::tx_band::TX_BAND_2: return "2"; case rhodium_radio_control_impl::tx_band::TX_BAND_3: return "3"; case rhodium_radio_control_impl::tx_band::TX_BAND_4: return "4"; case rhodium_radio_control_impl::tx_band::TX_BAND_5: return "5"; case rhodium_radio_control_impl::tx_band::TX_BAND_6: return "6"; case rhodium_radio_control_impl::tx_band::TX_BAND_7: return "7"; case rhodium_radio_control_impl::tx_band::TX_BAND_INVALID: return "INVALID"; default: UHD_THROW_INVALID_CODE_PATH(); } } } // namespace void rhodium_radio_control_impl::_update_rx_freq_switches(const double freq) { RFNOC_LOG_TRACE("Update all RX freq related switches. f=" << freq << " Hz"); const auto band = _map_freq_to_rx_band(freq); RFNOC_LOG_TRACE("Selected band " << rx_band_to_log(band)); // select values for lowband/highband switches const bool is_lowband = (band == rx_band::RX_BAND_0); auto rx_sw2_sw7 = is_lowband ? rhodium_cpld_ctrl::RX_SW2_SW7_LOWBANDFILTERBANK : rhodium_cpld_ctrl::RX_SW2_SW7_HIGHBANDFILTERBANK; auto rx_hb_lb_sel = is_lowband ? rhodium_cpld_ctrl::RX_HB_LB_SEL_LOWBAND : rhodium_cpld_ctrl::RX_HB_LB_SEL_HIGHBAND; // select values for filter bank switches rhodium_cpld_ctrl::rx_sw3_t rx_sw3; rhodium_cpld_ctrl::rx_sw4_sw5_t rx_sw4_sw5; rhodium_cpld_ctrl::rx_sw6_t rx_sw6; switch (band) { case rx_band::RX_BAND_0: // Low band doesn't use the filter banks, use configuration for band 1 case rx_band::RX_BAND_1: rx_sw3 = rhodium_cpld_ctrl::RX_SW3_TOSWITCH4; rx_sw4_sw5 = rhodium_cpld_ctrl::RX_SW4_SW5_FILTER0450X0760MHZ; rx_sw6 = rhodium_cpld_ctrl::RX_SW6_FROMSWITCH5; break; case rx_band::RX_BAND_2: rx_sw3 = rhodium_cpld_ctrl::RX_SW3_TOSWITCH4; rx_sw4_sw5 = rhodium_cpld_ctrl::RX_SW4_SW5_FILTER0760X1100MHZ; rx_sw6 = rhodium_cpld_ctrl::RX_SW6_FROMSWITCH5; break; case rx_band::RX_BAND_3: rx_sw3 = rhodium_cpld_ctrl::RX_SW3_TOSWITCH4; rx_sw4_sw5 = rhodium_cpld_ctrl::RX_SW4_SW5_FILTER1100X1410MHZ; rx_sw6 = rhodium_cpld_ctrl::RX_SW6_FROMSWITCH5; break; case rx_band::RX_BAND_4: rx_sw3 = rhodium_cpld_ctrl::RX_SW3_TOSWITCH4; rx_sw4_sw5 = rhodium_cpld_ctrl::RX_SW4_SW5_FILTER1410X2050MHZ; rx_sw6 = rhodium_cpld_ctrl::RX_SW6_FROMSWITCH5; break; case rx_band::RX_BAND_5: rx_sw3 = rhodium_cpld_ctrl::RX_SW3_TOFILTER2050X3000MHZ; rx_sw4_sw5 = rhodium_cpld_ctrl::RX_SW4_SW5_FILTER0450X0760MHZ; rx_sw6 = rhodium_cpld_ctrl::RX_SW6_FROMFILTER2050X3000MHZ; break; case rx_band::RX_BAND_6: rx_sw3 = rhodium_cpld_ctrl::RX_SW3_TOFILTER3000X4500MHZ; rx_sw4_sw5 = rhodium_cpld_ctrl::RX_SW4_SW5_FILTER0450X0760MHZ; rx_sw6 = rhodium_cpld_ctrl::RX_SW6_FROMFILTER3000X4500MHZ; break; case rx_band::RX_BAND_7: rx_sw3 = rhodium_cpld_ctrl::RX_SW3_TOFILTER4500X6000MHZ; rx_sw4_sw5 = rhodium_cpld_ctrl::RX_SW4_SW5_FILTER0450X0760MHZ; rx_sw6 = rhodium_cpld_ctrl::RX_SW6_FROMFILTER4500X6000MHZ; break; case rx_band::RX_BAND_INVALID: throw uhd::runtime_error( str(boost::format("Cannot map RX frequency to band: %f") % freq)); default: UHD_THROW_INVALID_CODE_PATH(); } // commit settings to cpld _cpld->set_rx_switches(rx_sw2_sw7, rx_sw3, rx_sw4_sw5, rx_sw6, rx_hb_lb_sel); } void rhodium_radio_control_impl::_update_tx_freq_switches(const double freq) { RFNOC_LOG_TRACE("Update all TX freq related switches. f=" << freq << " Hz"); const auto band = _map_freq_to_tx_band(freq); RFNOC_LOG_TRACE("Selected band " << tx_band_to_log(band)); // select values for lowband/highband switches const bool is_lowband = (band == tx_band::TX_BAND_0); auto tx_hb_lb_sel = is_lowband ? rhodium_cpld_ctrl::TX_HB_LB_SEL_LOWBAND : rhodium_cpld_ctrl::TX_HB_LB_SEL_HIGHBAND; // select values for filter bank switches rhodium_cpld_ctrl::tx_sw2_t tx_sw2; rhodium_cpld_ctrl::tx_sw3_sw4_t tx_sw3_sw4; rhodium_cpld_ctrl::tx_sw5_t tx_sw5; switch (band) { case tx_band::TX_BAND_0: // Low band doesn't use the filter banks, use configuration for band 1 case tx_band::TX_BAND_1: tx_sw2 = rhodium_cpld_ctrl::TX_SW2_FROMSWITCH3; tx_sw3_sw4 = rhodium_cpld_ctrl::TX_SW3_SW4_FROMTXFILTERLP0650MHZ; tx_sw5 = rhodium_cpld_ctrl::TX_SW5_TOSWITCH4; break; case tx_band::TX_BAND_2: tx_sw2 = rhodium_cpld_ctrl::TX_SW2_FROMSWITCH3; tx_sw3_sw4 = rhodium_cpld_ctrl::TX_SW3_SW4_FROMTXFILTERLP1000MHZ; tx_sw5 = rhodium_cpld_ctrl::TX_SW5_TOSWITCH4; break; case tx_band::TX_BAND_3: tx_sw2 = rhodium_cpld_ctrl::TX_SW2_FROMSWITCH3; tx_sw3_sw4 = rhodium_cpld_ctrl::TX_SW3_SW4_FROMTXFILTERLP1350MHZ; tx_sw5 = rhodium_cpld_ctrl::TX_SW5_TOSWITCH4; break; case tx_band::TX_BAND_4: tx_sw2 = rhodium_cpld_ctrl::TX_SW2_FROMSWITCH3; tx_sw3_sw4 = rhodium_cpld_ctrl::TX_SW3_SW4_FROMTXFILTERLP1900MHZ; tx_sw5 = rhodium_cpld_ctrl::TX_SW5_TOSWITCH4; break; case tx_band::TX_BAND_5: tx_sw2 = rhodium_cpld_ctrl::TX_SW2_FROMTXFILTERLP3000MHZ; tx_sw3_sw4 = rhodium_cpld_ctrl::TX_SW3_SW4_FROMTXFILTERLP0650MHZ; tx_sw5 = rhodium_cpld_ctrl::TX_SW5_TOTXFILTERLP3000MHZ; break; case tx_band::TX_BAND_6: tx_sw2 = rhodium_cpld_ctrl::TX_SW2_FROMTXFILTERLP4100MHZ; tx_sw3_sw4 = rhodium_cpld_ctrl::TX_SW3_SW4_FROMTXFILTERLP0650MHZ; tx_sw5 = rhodium_cpld_ctrl::TX_SW5_TOTXFILTERLP4100MHZ; break; case tx_band::TX_BAND_7: tx_sw2 = rhodium_cpld_ctrl::TX_SW2_FROMTXFILTERLP6000MHZ; tx_sw3_sw4 = rhodium_cpld_ctrl::TX_SW3_SW4_FROMTXFILTERLP0650MHZ; tx_sw5 = rhodium_cpld_ctrl::TX_SW5_TOTXFILTERLP6000MHZ; break; case tx_band::TX_BAND_INVALID: throw uhd::runtime_error( str(boost::format("Cannot map TX frequency to band: %f") % freq)); default: UHD_THROW_INVALID_CODE_PATH(); } // commit settings to cpld _cpld->set_tx_switches(tx_sw2, tx_sw3_sw4, tx_sw5, tx_hb_lb_sel); } void rhodium_radio_control_impl::_update_rx_input_switches(const std::string& input) { RFNOC_LOG_TRACE("Update all RX input related switches. input=" << input); const rhodium_cpld_ctrl::cal_iso_sw_t cal_iso = (input == "CAL") ? rhodium_cpld_ctrl::CAL_ISO_CALLOOPBACK : rhodium_cpld_ctrl::CAL_ISO_ISOLATION; const rhodium_cpld_ctrl::rx_sw1_t sw1 = [input] { if (input == "TX/RX") { return rhodium_cpld_ctrl::RX_SW1_FROMTXRXINPUT; } else if (input == "RX2") { return rhodium_cpld_ctrl::RX_SW1_FROMRX2INPUT; } else if (input == "CAL") { return rhodium_cpld_ctrl::RX_SW1_FROMCALLOOPBACK; } else if (input == "TERM") { return rhodium_cpld_ctrl::RX_SW1_ISOLATION; } else { throw uhd::runtime_error( "Invalid antenna in _update_rx_input_switches: " + input); } }(); RFNOC_LOG_TRACE("Selected switch values:" " sw1=" << sw1 << " cal_iso=" << cal_iso); _cpld->set_rx_input_switches(sw1, cal_iso); } void rhodium_radio_control_impl::_update_tx_output_switches(const std::string& output) { RFNOC_LOG_TRACE("Update all TX output related switches. output=" << output); rhodium_cpld_ctrl::tx_sw1_t sw1; if (output == "TX/RX") { // SW1 needs to select low/high band if (_is_tx_lowband(get_tx_frequency(0))) { sw1 = rhodium_cpld_ctrl::TX_SW1_TOLOWBAND; } else { sw1 = rhodium_cpld_ctrl::TX_SW1_TOSWITCH2; } } else if (output == "CAL") { sw1 = rhodium_cpld_ctrl::TX_SW1_TOCALLOOPBACK; } else if (output == "TERM") { sw1 = rhodium_cpld_ctrl::TX_SW1_ISOLATION; } else { throw uhd::runtime_error( "Invalid antenna in _update_tx_output_switches: " + output); } RFNOC_LOG_TRACE("Selected switch values: sw1=" << sw1); _cpld->set_tx_output_switches(sw1); }