diff options
author | Martin Braun <martin.braun@ettus.com> | 2019-08-20 10:00:47 -0700 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 12:16:25 -0800 |
commit | 7d69dcdcc318ccdf87038b732acbf2bf7c087b60 (patch) | |
tree | 8179f2f4a14be591d7c856f77f13687b45f9a454 /host/lib/usrp/x300 | |
parent | 1ac6e6f56100a7e8186481ab0715937759f52737 (diff) | |
download | uhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.tar.gz uhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.tar.bz2 uhd-7d69dcdcc318ccdf87038b732acbf2bf7c087b60.zip |
Remove proto-RFNoC files
This commit removes all files and parts of files that are used by
proto-RFNoC only.
uhd: Fix include CMakeLists.txt, add missing files
Diffstat (limited to 'host/lib/usrp/x300')
-rw-r--r-- | host/lib/usrp/x300/x300_eth_mgr.cpp | 80 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_pcie_mgr.cpp | 102 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_radio_ctrl_impl.cpp | 1577 | ||||
-rw-r--r-- | host/lib/usrp/x300/x300_radio_ctrl_impl.hpp | 246 |
4 files changed, 91 insertions, 1914 deletions
diff --git a/host/lib/usrp/x300/x300_eth_mgr.cpp b/host/lib/usrp/x300/x300_eth_mgr.cpp index b1d9f40ee..8ff63b050 100644 --- a/host/lib/usrp/x300/x300_eth_mgr.cpp +++ b/host/lib/usrp/x300/x300_eth_mgr.cpp @@ -239,46 +239,46 @@ both_links_t eth_manager::get_links(link_type_t link_type, //#ifdef HAVE_DPDK // auto& dpdk_ctx = uhd::transport::uhd_dpdk_ctx::get(); - // default_buff_args.num_recv_frames = ETH_MSG_NUM_FRAMES; - // default_buff_args.num_send_frames = ETH_MSG_NUM_FRAMES; - // if (link_type == link_type_t::CTRL) { - //// Increasing number of recv frames here because ctrl_iface uses it - //// to determine how many control packets can be in flight before it - //// must wait for an ACK - // default_buff_args.num_recv_frames = - // uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE; - //} else if (xport_type == uhd::usrp::device3_impl::TX_DATA) { - // size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE - //? GE_DATA_FRAME_SEND_SIZE - //: XGE_DATA_FRAME_SEND_SIZE; - // default_buff_args.send_frame_size = args.cast<size_t>( - //"send_frame_size", std::min(default_frame_size, send_mtu)); - // default_buff_args.num_send_frames = - // args.cast<size_t>("num_send_frames", default_buff_args.num_send_frames); - // default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); - //} else if (xport_type == uhd::usrp::device3_impl::RX_DATA) { - // size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE - //? GE_DATA_FRAME_RECV_SIZE - //: XGE_DATA_FRAME_RECV_SIZE; - // default_buff_args.recv_frame_size = args.cast<size_t>( - //"recv_frame_size", std::min(default_frame_size, recv_mtu)); - // default_buff_args.num_recv_frames = - // args.cast<size_t>("num_recv_frames", default_buff_args.num_recv_frames); - // default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); - //} - - // int dpdk_port_id = dpdk_ctx.get_route(conn.addr); - // if (dpdk_port_id < 0) { - // throw uhd::runtime_error( - //"Could not find a DPDK port with route to " + conn.addr); - //} - // auto recv = transport::dpdk_zero_copy::make(dpdk_ctx, - //(const unsigned int)dpdk_port_id, - // conn.addr, - // BOOST_STRINGIZE(X300_VITA_UDP_PORT), - //"0", - // default_buff_args, - // uhd::device_addr_t()); +// default_buff_args.num_recv_frames = ETH_MSG_NUM_FRAMES; +// default_buff_args.num_send_frames = ETH_MSG_NUM_FRAMES; +// if (link_type == link_type_t::CTRL) { +//// Increasing number of recv frames here because ctrl_iface uses it +//// to determine how many control packets can be in flight before it +//// must wait for an ACK +// default_buff_args.num_recv_frames = +// uhd::rfnoc::CMD_FIFO_SIZE / uhd::rfnoc::MAX_CMD_PKT_SIZE; +//} else if (xport_type == uhd::transport::link_type_t::TX_DATA) { +// size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE +//? GE_DATA_FRAME_SEND_SIZE +//: XGE_DATA_FRAME_SEND_SIZE; +// default_buff_args.send_frame_size = args.cast<size_t>( +//"send_frame_size", std::min(default_frame_size, send_mtu)); +// default_buff_args.num_send_frames = +// args.cast<size_t>("num_send_frames", default_buff_args.num_send_frames); +// default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); +//} else if (xport_type == uhd::transport::link_type_t::RX_DATA) { +// size_t default_frame_size = conn.link_rate == MAX_RATE_1GIGE +//? GE_DATA_FRAME_RECV_SIZE +//: XGE_DATA_FRAME_RECV_SIZE; +// default_buff_args.recv_frame_size = args.cast<size_t>( +//"recv_frame_size", std::min(default_frame_size, recv_mtu)); +// default_buff_args.num_recv_frames = +// args.cast<size_t>("num_recv_frames", default_buff_args.num_recv_frames); +// default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); +//} + +// int dpdk_port_id = dpdk_ctx.get_route(conn.addr); +// if (dpdk_port_id < 0) { +// throw uhd::runtime_error( +//"Could not find a DPDK port with route to " + conn.addr); +//} +// auto recv = transport::dpdk_zero_copy::make(dpdk_ctx, +//(const unsigned int)dpdk_port_id, +// conn.addr, +// BOOST_STRINGIZE(X300_VITA_UDP_PORT), +//"0", +// default_buff_args, +// uhd::device_addr_t()); //#else UHD_LOG_WARNING("X300", "Cannot create DPDK transport, falling back to UDP"); diff --git a/host/lib/usrp/x300/x300_pcie_mgr.cpp b/host/lib/usrp/x300/x300_pcie_mgr.cpp index 220a96530..6560f2770 100644 --- a/host/lib/usrp/x300/x300_pcie_mgr.cpp +++ b/host/lib/usrp/x300/x300_pcie_mgr.cpp @@ -275,13 +275,13 @@ uint32_t pcie_manager::allocate_pcie_dma_chan( const rfnoc::sep_id_t& /*remote_epid*/, const link_type_t /*link_type*/) { throw uhd::not_implemented_error("allocate_pcie_dma_chan()"); - //constexpr uint32_t CTRL_CHANNEL = 0; - //constexpr uint32_t ASYNC_MSG_CHANNEL = 1; - //constexpr uint32_t FIRST_DATA_CHANNEL = 2; - //if (link_type == uhd::usrp::device3_impl::CTRL) { - //return CTRL_CHANNEL; - //} else if (link_type == uhd::usrp::device3_impl::ASYNC_MSG) { - //return ASYNC_MSG_CHANNEL; + // constexpr uint32_t CTRL_CHANNEL = 0; + // constexpr uint32_t ASYNC_MSG_CHANNEL = 1; + // constexpr uint32_t FIRST_DATA_CHANNEL = 2; + // if (link_type == uhd::transport::link_type_t::CTRL) { + // return CTRL_CHANNEL; + //} else if (link_type == uhd::transport::link_type_t::ASYNC_MSG) { + // return ASYNC_MSG_CHANNEL; //} else { //// sid_t has no comparison defined, so we need to convert it uint32_t //uint32_t raw_sid = tx_sid.get(); @@ -330,50 +330,50 @@ both_links_t pcie_manager::get_links(link_type_t /*link_type*/, + std::to_string(local_device_id) + ", no such device associated with this motherboard!"); } - //zero_copy_xport_params default_buff_args; - //xports.endianness = ENDIANNESS_LITTLE; - //xports.lossless = true; - //const uint32_t dma_channel_num = allocate_pcie_dma_chan(xports.send_sid, xport_type); - //if (xport_type == uhd::usrp::device3_impl::CTRL) { - //// Transport for control stream - //if (not _ctrl_dma_xport) { - //// One underlying DMA channel will handle - //// all control traffic - //_ctrl_dma_xport = - //make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_CTRL_XPORTS); - //} - //// Create a virtual control transport - //xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst()); - //} else if (xport_type == uhd::usrp::device3_impl::ASYNC_MSG) { - //// Transport for async message stream - //if (not _async_msg_dma_xport) { - //// One underlying DMA channel will handle - //// all async message traffic - //_async_msg_dma_xport = - //make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_ASYNC_XPORTS); - //} - //// Create a virtual async message transport - //xports.recv = _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst()); - //} else if (xport_type == uhd::usrp::device3_impl::TX_DATA) { - //default_buff_args.send_frame_size = args.cast<size_t>( - //"send_frame_size", std::min(send_mtu, PCIE_TX_DATA_FRAME_SIZE)); - //default_buff_args.num_send_frames = - //args.cast<size_t>("num_send_frames", PCIE_TX_DATA_NUM_FRAMES); - //default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); - //default_buff_args.recv_frame_size = PCIE_MSG_FRAME_SIZE; - //default_buff_args.num_recv_frames = PCIE_MSG_NUM_FRAMES; - //xports.recv = nirio_zero_copy::make( - //_rio_fpga_interface, dma_channel_num, default_buff_args); - //} else if (xport_type == uhd::usrp::device3_impl::RX_DATA) { - //default_buff_args.send_frame_size = PCIE_MSG_FRAME_SIZE; - //default_buff_args.num_send_frames = PCIE_MSG_NUM_FRAMES; - //default_buff_args.recv_frame_size = args.cast<size_t>( - //"recv_frame_size", std::min(recv_mtu, PCIE_RX_DATA_FRAME_SIZE)); - //default_buff_args.num_recv_frames = - //args.cast<size_t>("num_recv_frames", PCIE_RX_DATA_NUM_FRAMES); - //default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); - //xports.recv = nirio_zero_copy::make( - //_rio_fpga_interface, dma_channel_num, default_buff_args); + // zero_copy_xport_params default_buff_args; + // xports.endianness = ENDIANNESS_LITTLE; + // xports.lossless = true; + // const uint32_t dma_channel_num = allocate_pcie_dma_chan(xports.send_sid, + // xport_type); if (xport_type == uhd::transport::link_type_t::CTRL) { + //// Transport for control stream + // if (not _ctrl_dma_xport) { + //// One underlying DMA channel will handle + //// all control traffic + //_ctrl_dma_xport = + // make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_CTRL_XPORTS); + //} + //// Create a virtual control transport + // xports.recv = _ctrl_dma_xport->make_stream(xports.recv_sid.get_dst()); + //} else if (xport_type == uhd::transport::link_type_t::ASYNC_MSG) { + //// Transport for async message stream + // if (not _async_msg_dma_xport) { + //// One underlying DMA channel will handle + //// all async message traffic + //_async_msg_dma_xport = + // make_muxed_pcie_msg_xport(dma_channel_num, PCIE_MAX_MUXED_ASYNC_XPORTS); + //} + //// Create a virtual async message transport + // xports.recv = _async_msg_dma_xport->make_stream(xports.recv_sid.get_dst()); + //} else if (xport_type == uhd::transport::link_type_t::TX_DATA) { + // default_buff_args.send_frame_size = args.cast<size_t>( + //"send_frame_size", std::min(send_mtu, PCIE_TX_DATA_FRAME_SIZE)); + // default_buff_args.num_send_frames = + // args.cast<size_t>("num_send_frames", PCIE_TX_DATA_NUM_FRAMES); + // default_buff_args.send_buff_size = args.cast<size_t>("send_buff_size", 0); + // default_buff_args.recv_frame_size = PCIE_MSG_FRAME_SIZE; + // default_buff_args.num_recv_frames = PCIE_MSG_NUM_FRAMES; + // xports.recv = nirio_zero_copy::make( + //_rio_fpga_interface, dma_channel_num, default_buff_args); + //} else if (xport_type == uhd::transport::link_type_t::RX_DATA) { + // default_buff_args.send_frame_size = PCIE_MSG_FRAME_SIZE; + // default_buff_args.num_send_frames = PCIE_MSG_NUM_FRAMES; + // default_buff_args.recv_frame_size = args.cast<size_t>( + //"recv_frame_size", std::min(recv_mtu, PCIE_RX_DATA_FRAME_SIZE)); + // default_buff_args.num_recv_frames = + // args.cast<size_t>("num_recv_frames", PCIE_RX_DATA_NUM_FRAMES); + // default_buff_args.recv_buff_size = args.cast<size_t>("recv_buff_size", 0); + // xports.recv = nirio_zero_copy::make( + //_rio_fpga_interface, dma_channel_num, default_buff_args); //} //xports.send = xports.recv; diff --git a/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp b/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp deleted file mode 100644 index c280f77c5..000000000 --- a/host/lib/usrp/x300/x300_radio_ctrl_impl.cpp +++ /dev/null @@ -1,1577 +0,0 @@ -// -// Copyright 2015-2017 Ettus Research, A National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "x300_radio_ctrl_impl.hpp" -#include "x300_dboard_iface.hpp" -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/transport/chdr.hpp> -#include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/usrp/dboard_iface.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/utils/math.hpp> -#include <uhd/utils/safe_call.hpp> -#include <uhdlib/rfnoc/wb_iface_adapter.hpp> -#include <uhdlib/usrp/common/apply_corrections.hpp> -#include <uhdlib/usrp/cores/gpio_atr_3000.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/date_time/posix_time/posix_time_io.hpp> -#include <boost/make_shared.hpp> -#include <chrono> -#include <thread> -#include <bitset> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::rfnoc; -using namespace uhd::usrp::x300; - -static const size_t IO_MASTER_RADIO = 0; - -namespace { - -gain_fcns_t make_gain_fcns_from_subtree(property_tree::sptr subtree) -{ - gain_fcns_t gain_fcns; - gain_fcns.get_range = [subtree]() { - return subtree->access<meta_range_t>("range").get(); - }; - gain_fcns.get_value = [subtree]() { return subtree->access<double>("value").get(); }; - gain_fcns.set_value = [subtree](const double gain) { - subtree->access<double>("value").set(gain); - }; - return gain_fcns; -} - -} // namespace - -/**************************************************************************** - * Structors - ***************************************************************************/ -UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(x300_radio_ctrl) -, _ignore_cal_file(false) -{ - UHD_RFNOC_BLOCK_TRACE() << "x300_radio_ctrl_impl::ctor() "; - - //////////////////////////////////////////////////////////////////// - // Set up basic info - //////////////////////////////////////////////////////////////////// - _radio_type = (get_block_id().get_block_count() == 0) ? PRIMARY : SECONDARY; - _radio_slot = (get_block_id().get_block_count() == 0) ? "A" : "B"; - _radio_clk_rate = _tree->access<double>("master_clock_rate").get(); - - //////////////////////////////////////////////////////////////////// - // Set up peripherals - //////////////////////////////////////////////////////////////////// - wb_iface::sptr ctrl = _get_ctrl(IO_MASTER_RADIO); - _regs = boost::make_shared<radio_regmap_t>(_radio_type == PRIMARY ? 0 : 1); - _regs->initialize(*ctrl, true); - - // Only Radio0 has the ADC/DAC reset bits. Those bits are reserved for Radio1 - if (_radio_type == PRIMARY) { - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0); - _regs->misc_outs_reg.flush(); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 0); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 1); - _regs->misc_outs_reg.flush(); - } - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_ENABLED, 1); - - //////////////////////////////////////////////////////////////// - // Setup peripherals - //////////////////////////////////////////////////////////////// - _spi = spi_core_3000::make(ctrl, - regs::sr_addr(radio_ctrl_impl::regs::SPI), - regs::rb_addr(radio_ctrl_impl::regs::RB_SPI)); - _adc = x300_adc_ctrl::make(_spi, DB_ADC_SEN); - _dac = x300_dac_ctrl::make(_spi, DB_DAC_SEN, _radio_clk_rate); - - if (_radio_type == PRIMARY) { - _fp_gpio = gpio_atr::gpio_atr_3000::make( - ctrl, regs::sr_addr(regs::FP_GPIO), regs::rb_addr(regs::RB_FP_GPIO)); - for (const gpio_atr::gpio_attr_map_t::value_type attr : gpio_atr::gpio_attr_map) { - switch (attr.first) { - case usrp::gpio_atr::GPIO_SRC: - _tree - ->create<std::vector<std::string>>( - fs_path("gpio") / "FP0" / attr.second) - .set(std::vector<std::string>( - 32, usrp::gpio_atr::default_attr_value_map.at(attr.first))) - .add_coerced_subscriber([this](const std::vector<std::string>&) { - throw uhd::runtime_error("This device does not support " - "setting the GPIO_SRC attribute."); - }); - break; - case usrp::gpio_atr::GPIO_CTRL: - case usrp::gpio_atr::GPIO_DDR: - _tree - ->create<std::vector<std::string>>( - fs_path("gpio") / "FP0" / attr.second) - .set(std::vector<std::string>( - 32, usrp::gpio_atr::default_attr_value_map.at(attr.first))) - .add_coerced_subscriber( - [this, attr](const std::vector<std::string> str_val) { - uint32_t val = 0; - for (size_t i = 0; i < str_val.size(); i++) { - val += usrp::gpio_atr::gpio_attr_value_pair - .at(attr.second) - .at(str_val[i]) - << i; - } - _fp_gpio->set_gpio_attr(attr.first, val); - }); - break; - case usrp::gpio_atr::GPIO_READBACK: - _tree->create<uint32_t>(fs_path("gpio") / "FP0" / "READBACK") - .set_publisher([this]() { return _fp_gpio->read_gpio(); }); - break; - default: - _tree->create<uint32_t>(fs_path("gpio") / "FP0" / attr.second) - .set(0) - .add_coerced_subscriber([this, attr](const uint32_t val) { - _fp_gpio->set_gpio_attr(attr.first, val); - }); - } - } - } - - //////////////////////////////////////////////////////////////// - // create legacy codec control objects - //////////////////////////////////////////////////////////////// - _tree->create<int>( - "rx_codecs" / _radio_slot / "gains"); // phony property so this dir exists - _tree->create<int>( - "tx_codecs" / _radio_slot / "gains"); // phony property so this dir exists - _tree->create<std::string>("rx_codecs" / _radio_slot / "name").set("ads62p48"); - _tree->create<std::string>("tx_codecs" / _radio_slot / "name").set("ad9146"); - - _tree->create<meta_range_t>("rx_codecs" / _radio_slot / "gains" / "digital" / "range") - .set(meta_range_t(0, 6.0, 0.5)); - _tree->create<double>("rx_codecs" / _radio_slot / "gains" / "digital" / "value") - .add_coerced_subscriber(boost::bind(&x300_adc_ctrl::set_gain, _adc, _1)) - .set(0); - - //////////////////////////////////////////////////////////////// - // create front-end objects - //////////////////////////////////////////////////////////////// - for (size_t i = 0; i < _get_num_radios(); i++) { - _leds[i] = gpio_atr::gpio_atr_3000::make_write_only( - _get_ctrl(i), regs::sr_addr(regs::LEDS)); - _leds[i]->set_atr_mode( - usrp::gpio_atr::MODE_ATR, usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL); - - _rx_fe_map[i].core = rx_frontend_core_3000::make( - _get_ctrl(i), regs::sr_addr(x300_regs::RX_FE_BASE)); - _rx_fe_map[i].core->set_adc_rate(_radio_clk_rate); - _rx_fe_map[i].core->set_dc_offset(rx_frontend_core_3000::DEFAULT_DC_OFFSET_VALUE); - _rx_fe_map[i].core->set_dc_offset_auto( - rx_frontend_core_3000::DEFAULT_DC_OFFSET_ENABLE); - _rx_fe_map[i].core->populate_subtree( - _tree->subtree(_root_path / "rx_fe_corrections" / i)); - - _tx_fe_map[i].core = tx_frontend_core_200::make( - _get_ctrl(i), regs::sr_addr(x300_regs::TX_FE_BASE)); - _tx_fe_map[i].core->set_dc_offset(tx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); - _tx_fe_map[i].core->set_iq_balance( - tx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); - _tx_fe_map[i].core->populate_subtree( - _tree->subtree(_root_path / "tx_fe_corrections" / i)); - - //////////////////////////////////////////////////////////////// - // Bind the daughterboard command time to the motherboard level property - //////////////////////////////////////////////////////////////// - - if (_tree->exists(fs_path("time") / "cmd")) { - _tree->access<time_spec_t>(fs_path("time") / "cmd") - .add_coerced_subscriber( - boost::bind(&x300_radio_ctrl_impl::set_fe_cmd_time, this, _1, i)); - } - } - - //////////////////////////////////////////////////////////////// - // Update default SPP (overwrites the default value from the XML file) - //////////////////////////////////////////////////////////////// - const size_t max_bytes_header = - uhd::transport::vrt::chdr::max_if_hdr_words64 * sizeof(uint64_t); - const size_t default_spp = - (_tree->access<size_t>("mtu/recv").get() - max_bytes_header) - / (2 * sizeof(int16_t)); - _tree->access<int>(get_arg_path("spp") / "value").set(default_spp); -} - -x300_radio_ctrl_impl::~x300_radio_ctrl_impl() -{ - UHD_SAFE_CALL( - // Tear down our part of the tree: - _tree->remove(fs_path("rx_codecs" / _radio_slot)); - _tree->remove(fs_path("tx_codecs" / _radio_slot)); - _tree->remove(_root_path / "rx_fe_corrections"); - _tree->remove(_root_path / "tx_fe_corrections"); - if (_radio_type == PRIMARY) { - for (const gpio_atr::gpio_attr_map_t::value_type attr : - gpio_atr::gpio_attr_map) { - _tree->remove(fs_path("gpio") / "FP0" / attr.second); - } - } - - // Reset peripherals - if (_radio_type == PRIMARY) { - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0); - } _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::DAC_ENABLED, 0); - _regs->misc_outs_reg.flush();) -} - -/**************************************************************************** - * API calls - ***************************************************************************/ -double x300_radio_ctrl_impl::set_rate(double rate) -{ - const double actual_rate = get_rate(); - if (not uhd::math::frequencies_are_equal(rate, actual_rate)) { - UHD_LOGGER_WARNING("X300 RADIO") - << "Requesting invalid sampling rate from device: " << rate / 1e6 - << " MHz. Actual rate is: " << actual_rate / 1e6 << " MHz."; - } - // On X3x0, tick rate can't actually be changed at runtime - return actual_rate; -} - -void x300_radio_ctrl_impl::set_fe_cmd_time(const time_spec_t& time, const size_t chan) -{ - if (_tree->exists(fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "time" / "cmd"))) { - _tree - ->access<time_spec_t>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "time" / "cmd")) - .set(time); - } -} - -void x300_radio_ctrl_impl::set_tx_antenna(const std::string& ant, const size_t chan) -{ - _tree - ->access<std::string>( - fs_path("dboards" / _radio_slot / "tx_frontends" - / _tx_fe_map.at(chan).db_fe_name / "antenna" / "value")) - .set(ant); -} - -std::string x300_radio_ctrl_impl::get_tx_antenna(const size_t chan) -{ - return _tree - ->access<std::string>( - fs_path("dboards" / _radio_slot / "tx_frontends" - / _tx_fe_map.at(chan).db_fe_name / "antenna" / "value")) - .get(); -} - -void x300_radio_ctrl_impl::set_rx_antenna(const std::string& ant, const size_t chan) -{ - _tree - ->access<std::string>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "antenna" / "value")) - .set(ant); -} - -std::string x300_radio_ctrl_impl::get_rx_antenna(const size_t chan) -{ - return _tree - ->access<std::string>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "antenna" / "value")) - .get(); -} - -double x300_radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan) -{ - return _tree - ->access<double>(fs_path("dboards" / _radio_slot / "tx_frontends" - / _tx_fe_map.at(chan).db_fe_name / "freq" / "value")) - .set(freq) - .get(); -} - -double x300_radio_ctrl_impl::get_tx_frequency(const size_t chan) -{ - return _tree - ->access<double>(fs_path("dboards" / _radio_slot / "tx_frontends" - / _tx_fe_map.at(chan).db_fe_name / "freq" / "value")) - .get(); -} - -double x300_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan) -{ - return _tree - ->access<double>(fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "freq" / "value")) - .set(freq) - .get(); -} - -double x300_radio_ctrl_impl::get_rx_frequency(const size_t chan) -{ - return _tree - ->access<double>(fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "freq" / "value")) - .get(); -} - -double x300_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan) -{ - return _tree - ->access<double>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "bandwidth" / "value")) - .set(bandwidth) - .get(); -} - -double x300_radio_ctrl_impl::get_rx_bandwidth(const size_t chan) -{ - return _tree - ->access<double>( - fs_path("dboards" / _radio_slot / "rx_frontends" - / _rx_fe_map.at(chan).db_fe_name / "bandwidth" / "value")) - .get(); -} - -double x300_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan) -{ - if (_tx_gain_groups.count(chan)) { - auto& gg = _tx_gain_groups.at(chan); - gg->set_value(gain); - return radio_ctrl_impl::set_tx_gain(gg->get_value(), chan); - } - return radio_ctrl_impl::set_tx_gain(0.0, chan); -} - -double x300_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan) -{ - auto& gg = _rx_gain_groups.at(chan); - gg->set_value(gain); - return radio_ctrl_impl::set_rx_gain(gg->get_value(), chan); -} - -double x300_radio_ctrl_impl::get_rx_gain(const size_t chan) -{ - return _rx_gain_groups.at(chan)->get_value(); -} - -std::vector<std::string> x300_radio_ctrl_impl::get_rx_lo_names(const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - std::vector<std::string> lo_names; - if (_tree->exists(rx_fe_fe_root / "los")) { - for (const std::string& name : _tree->list(rx_fe_fe_root / "los")) { - lo_names.push_back(name); - } - } - return lo_names; -} - -std::vector<std::string> x300_radio_ctrl_impl::get_rx_lo_sources( - const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) { - // Special value ALL_LOS support atomically sets the source for all LOs - return _tree - ->access<std::vector<std::string>>( - rx_fe_fe_root / "los" / ALL_LOS / "source" / "options") - .get(); - } else { - return std::vector<std::string>(); - } - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree - ->access<std::vector<std::string>>( - rx_fe_fe_root / "los" / name / "source" / "options") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // If the daughterboard doesn't expose it's LO(s) then it can only be internal - return std::vector<std::string>(1, "internal"); - } -} - -void x300_radio_ctrl_impl::set_rx_lo_source( - const std::string& src, const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) { - // Special value ALL_LOS support atomically sets the source for all LOs - _tree - ->access<std::string>( - rx_fe_fe_root / "los" / ALL_LOS / "source" / "value") - .set(src); - } else { - for (const std::string& n : _tree->list(rx_fe_fe_root / "los")) { - this->set_rx_lo_source(src, n, chan); - } - } - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - _tree - ->access<std::string>( - rx_fe_fe_root / "los" / name / "source" / "value") - .set(src); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - throw uhd::runtime_error( - "This device does not support manual configuration of LOs"); - } -} - -const std::string x300_radio_ctrl_impl::get_rx_lo_source( - const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - // Special value ALL_LOS support atomically sets the source for all LOs - return _tree - ->access<std::string>( - rx_fe_fe_root / "los" / ALL_LOS / "source" / "value") - .get(); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree - ->access<std::string>( - rx_fe_fe_root / "los" / name / "source" / "value") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // If the daughterboard doesn't expose it's LO(s) then it can only be internal - return "internal"; - } -} - -void x300_radio_ctrl_impl::set_rx_lo_export_enabled( - bool enabled, const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - if (_tree->exists(rx_fe_fe_root / "los" / ALL_LOS)) { - // Special value ALL_LOS support atomically sets the source for all LOs - _tree->access<bool>(rx_fe_fe_root / "los" / ALL_LOS / "export") - .set(enabled); - } else { - for (const std::string& n : _tree->list(rx_fe_fe_root / "los")) { - this->set_rx_lo_export_enabled(enabled, n, chan); - } - } - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - _tree->access<bool>(rx_fe_fe_root / "los" / name / "export").set(enabled); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - throw uhd::runtime_error( - "This device does not support manual configuration of LOs"); - } -} - -bool x300_radio_ctrl_impl::get_rx_lo_export_enabled( - const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - // Special value ALL_LOS support atomically sets the source for all LOs - return _tree->access<bool>(rx_fe_fe_root / "los" / ALL_LOS / "export").get(); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree->access<bool>(rx_fe_fe_root / "los" / name / "export").get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // If the daughterboard doesn't expose it's LO(s), assume it cannot export - return false; - } -} - -double x300_radio_ctrl_impl::set_rx_lo_freq( - double freq, const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - throw uhd::runtime_error( - "LO frequency must be set for each stage individually"); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - _tree->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value") - .set(freq); - return _tree - ->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - throw uhd::runtime_error( - "This device does not support manual configuration of LOs"); - } -} - -double x300_radio_ctrl_impl::get_rx_lo_freq(const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - throw uhd::runtime_error( - "LO frequency must be retrieved for each stage individually"); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree - ->access<double>(rx_fe_fe_root / "los" / name / "freq" / "value") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // Return actual RF frequency if the daughterboard doesn't expose it's LO(s) - return _tree->access<double>(rx_fe_fe_root / "freq" / " value").get(); - } -} - -freq_range_t x300_radio_ctrl_impl::get_rx_lo_freq_range( - const std::string& name, const size_t chan) -{ - fs_path rx_fe_fe_root = fs_path( - "dboards" / _radio_slot / "rx_frontends" / _rx_fe_map.at(chan).db_fe_name); - - if (_tree->exists(rx_fe_fe_root / "los")) { - if (name == ALL_LOS) { - throw uhd::runtime_error( - "LO frequency range must be retrieved for each stage individually"); - } else { - if (_tree->exists(rx_fe_fe_root / "los")) { - return _tree - ->access<freq_range_t>( - rx_fe_fe_root / "los" / name / "freq" / "range") - .get(); - } else { - throw uhd::runtime_error("Could not find LO stage " + name); - } - } - } else { - // Return the actual RF range if the daughterboard doesn't expose it's LO(s) - return _tree->access<meta_range_t>(rx_fe_fe_root / "freq" / "range").get(); - } -} - -template <typename map_type> -static size_t _get_chan_from_map(std::map<size_t, map_type> map, const std::string& fe) -{ - for (auto it = map.begin(); it != map.end(); ++it) { - if (it->second.db_fe_name == fe) { - return it->first; - } - } - throw uhd::runtime_error( - str(boost::format("Invalid daughterboard frontend name: %s") % fe)); -} - -size_t x300_radio_ctrl_impl::get_chan_from_dboard_fe( - const std::string& fe, const uhd::direction_t direction) -{ - switch (direction) { - case uhd::TX_DIRECTION: - return _get_chan_from_map(_tx_fe_map, fe); - case uhd::RX_DIRECTION: - return _get_chan_from_map(_rx_fe_map, fe); - default: - UHD_THROW_INVALID_CODE_PATH(); - } -} - -std::string x300_radio_ctrl_impl::get_dboard_fe_from_chan( - const size_t chan, const uhd::direction_t direction) -{ - switch (direction) { - case uhd::TX_DIRECTION: - return _tx_fe_map.at(chan).db_fe_name; - case uhd::RX_DIRECTION: - return _rx_fe_map.at(chan).db_fe_name; - default: - UHD_THROW_INVALID_CODE_PATH(); - } -} - -double x300_radio_ctrl_impl::get_output_samp_rate(size_t chan) -{ - // TODO: chan should never be ANY_PORT, but due to our current graph search - // method, this can actually happen: - if (chan == ANY_PORT) { - chan = 0; - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_is_streamer_active(uhd::RX_DIRECTION, chan)) { - chan = i; - break; - } - } - } - return _rx_fe_map.at(chan).core->get_output_rate(); -} - -std::vector<std::string> x300_radio_ctrl_impl::get_gpio_banks() const -{ - std::vector<std::string> banks{"RX", "TX"}; - // These pairs are the same, but RXA/TXA are from pre-rfnoc era and are kept for - // backward compat: - banks.push_back("RX" + _radio_slot); - banks.push_back("TX" + _radio_slot); - if (_fp_gpio) { - banks.push_back("FP0"); - } - return banks; -} - -void x300_radio_ctrl_impl::set_gpio_attr(const std::string& bank, - const std::string& attr, - const uint32_t value, - const uint32_t mask) -{ - if (bank == "FP0" and _fp_gpio) { - std::vector<std::string> attr_value; - const auto attr_type = usrp::gpio_atr::gpio_attr_rev_map.at(attr); - switch (attr_type) { - case usrp::gpio_atr::GPIO_SRC: - case usrp::gpio_atr::GPIO_CTRL: - case usrp::gpio_atr::GPIO_DDR: { - attr_value = - _tree->access<std::vector<std::string>>(fs_path("gpio") / bank / attr) - .get(); - std::bitset<32> bit_mask = std::bitset<32>(mask); - std::bitset<32> new_value = std::bitset<32>(value); - for (size_t i = 0; i < bit_mask.size(); i++) { - if (bit_mask[i] == 1) { - attr_value[i] = - usrp::gpio_atr::attr_value_map.at(attr_type).at(new_value[i]); - } - } - _tree->access<std::vector<std::string>>(fs_path("gpio") / bank / attr) - .set(attr_value); - return; - } break; - default: { - const uint32_t curr_value = - _tree->access<uint32_t>(fs_path("gpio") / bank / attr).get(); - uint32_t new_value = (curr_value & ~mask) | (value & mask); - _tree->access<uint32_t>(fs_path("gpio") / bank / attr).set(new_value); - } break; - } - } - if (bank.size() > 2 and bank[1] == 'X') { - const std::string name = bank.substr(2); - const dboard_iface::unit_t unit = (bank[0] == 'R') ? dboard_iface::UNIT_RX - : dboard_iface::UNIT_TX; - dboard_iface::sptr iface = - _tree->access<dboard_iface::sptr>(fs_path("dboards") / name / "iface").get(); - if (attr == "CTRL") - iface->set_pin_ctrl(unit, uint16_t(value), uint16_t(mask)); - if (attr == "DDR") - iface->set_gpio_ddr(unit, uint16_t(value), uint16_t(mask)); - if (attr == "OUT") - iface->set_gpio_out(unit, uint16_t(value), uint16_t(mask)); - if (attr == "ATR_0X") - iface->set_atr_reg( - unit, gpio_atr::ATR_REG_IDLE, uint16_t(value), uint16_t(mask)); - if (attr == "ATR_RX") - iface->set_atr_reg( - unit, gpio_atr::ATR_REG_RX_ONLY, uint16_t(value), uint16_t(mask)); - if (attr == "ATR_TX") - iface->set_atr_reg( - unit, gpio_atr::ATR_REG_TX_ONLY, uint16_t(value), uint16_t(mask)); - if (attr == "ATR_XX") - iface->set_atr_reg( - unit, gpio_atr::ATR_REG_FULL_DUPLEX, uint16_t(value), uint16_t(mask)); - } -} - -uint32_t x300_radio_ctrl_impl::get_gpio_attr( - const std::string& bank, const std::string& attr) -{ - if (bank == "FP0" and _fp_gpio) { - const auto attr_type = usrp::gpio_atr::gpio_attr_rev_map.at(attr); - switch(attr_type) { - case usrp::gpio_atr::GPIO_SRC: - case usrp::gpio_atr::GPIO_CTRL: - case usrp::gpio_atr::GPIO_DDR: { - auto str_val = - _tree->access<std::vector<std::string>>( - fs_path("gpio") / bank / attr).get(); - uint32_t val = 0; - for (size_t i = 0; i < str_val.size(); i++) { - val += usrp::gpio_atr::gpio_attr_value_pair.at(attr).at(str_val[i]) << i; - } - return val; - } - break; - default: { - return _tree->access<uint32_t>(fs_path("gpio") / bank / attr).get(); - } - break; - } - } - if (bank.size() > 2 and bank[1] == 'X') { - const std::string name = bank.substr(2); - const dboard_iface::unit_t unit = (bank[0] == 'R') ? dboard_iface::UNIT_RX - : dboard_iface::UNIT_TX; - dboard_iface::sptr iface = - _tree->access<dboard_iface::sptr>(fs_path("dboards") / name / "iface").get(); - if (attr == "CTRL") - return iface->get_pin_ctrl(unit); - if (attr == "DDR") - return iface->get_gpio_ddr(unit); - if (attr == "OUT") - return iface->get_gpio_out(unit); - if (attr == "ATR_0X") - return iface->get_atr_reg(unit, gpio_atr::ATR_REG_IDLE); - if (attr == "ATR_RX") - return iface->get_atr_reg(unit, gpio_atr::ATR_REG_RX_ONLY); - if (attr == "ATR_TX") - return iface->get_atr_reg(unit, gpio_atr::ATR_REG_TX_ONLY); - if (attr == "ATR_XX") - return iface->get_atr_reg(unit, gpio_atr::ATR_REG_FULL_DUPLEX); - if (attr == "READBACK") - return iface->read_gpio(unit); - } - return 0; -} - -/**************************************************************************** - * Radio control and setup - ***************************************************************************/ -void x300_radio_ctrl_impl::setup_radio(uhd::i2c_iface::sptr zpu_i2c, - x300_clock_ctrl::sptr clock, - bool ignore_cal_file, - bool verbose) -{ - _self_cal_adc_capture_delay(verbose); - _ignore_cal_file = ignore_cal_file; - - //////////////////////////////////////////////////////////////////// - // create RF frontend interfacing - //////////////////////////////////////////////////////////////////// - static const size_t BASE_ADDR = 0x50; - static const size_t RX_EEPROM_ADDR = 0x5; - static const size_t TX_EEPROM_ADDR = 0x4; - static const size_t GDB_EEPROM_ADDR = 0x1; - const static std::vector<size_t> EEPROM_ADDRS{ - RX_EEPROM_ADDR, TX_EEPROM_ADDR, GDB_EEPROM_ADDR}; - const static std::vector<std::string> EEPROM_PATHS{ - "rx_eeprom", "tx_eeprom", "gdb_eeprom"}; - - const size_t DB_OFFSET = (_radio_slot == "A") ? 0x0 : 0x2; - const fs_path db_path = ("dboards" / _radio_slot); - for (size_t i = 0; i < EEPROM_ADDRS.size(); i++) { - const size_t addr = EEPROM_ADDRS[i] + DB_OFFSET; - // Load EEPROM - _db_eeproms[addr].load(*zpu_i2c, BASE_ADDR | addr); - // Add to tree - _tree->create<dboard_eeprom_t>(db_path / EEPROM_PATHS[i]) - .set(_db_eeproms[addr]) - .add_coerced_subscriber(boost::bind(&x300_radio_ctrl_impl::_set_db_eeprom, - this, - zpu_i2c, - (BASE_ADDR | addr), - _1)); - } - - // create a new dboard interface - x300_dboard_iface_config_t db_config; - db_config.gpio = gpio_atr::db_gpio_atr_3000::make(_get_ctrl(IO_MASTER_RADIO), - radio_ctrl_impl::regs::sr_addr(radio_ctrl_impl::regs::GPIO), - radio_ctrl_impl::regs::rb_addr(radio_ctrl_impl::regs::RB_DB_GPIO)); - db_config.spi = _spi; - db_config.rx_spi_slaveno = DB_RX_SEN; - db_config.tx_spi_slaveno = DB_TX_SEN; - db_config.i2c = zpu_i2c; - db_config.clock = clock; - db_config.which_rx_clk = (_radio_slot == "A") ? X300_CLOCK_WHICH_DB0_RX - : X300_CLOCK_WHICH_DB1_RX; - db_config.which_tx_clk = (_radio_slot == "A") ? X300_CLOCK_WHICH_DB0_TX - : X300_CLOCK_WHICH_DB1_TX; - db_config.dboard_slot = (_radio_slot == "A") ? 0 : 1; - db_config.cmd_time_ctrl = _get_ctrl(IO_MASTER_RADIO); - - // create a new dboard manager - boost::shared_ptr<x300_dboard_iface> db_iface = - boost::make_shared<x300_dboard_iface>(db_config); - _db_manager = dboard_manager::make(_db_eeproms[RX_EEPROM_ADDR + DB_OFFSET], - _db_eeproms[TX_EEPROM_ADDR + DB_OFFSET], - _db_eeproms[GDB_EEPROM_ADDR + DB_OFFSET], - db_iface, - _tree->subtree(db_path), - true // defer daughterboard intitialization - ); - - size_t rx_chan = 0, tx_chan = 0; - for (const std::string& fe : _db_manager->get_rx_frontends()) { - if (rx_chan >= _get_num_radios()) { - break; - } - _rx_fe_map[rx_chan].db_fe_name = fe; - db_iface->add_rx_fe(fe, _rx_fe_map[rx_chan].core); - const fs_path fe_path(db_path / "rx_frontends" / fe); - const std::string conn = _tree->access<std::string>(fe_path / "connection").get(); - const double if_freq = - (_tree->exists(fe_path / "if_freq/value")) - ? _tree->access<double>(fe_path / "if_freq/value").get() - : 0.0; - _rx_fe_map[rx_chan].core->set_fe_connection(usrp::fe_connection_t(conn, if_freq)); - rx_chan++; - } - for (const std::string& fe : _db_manager->get_tx_frontends()) { - if (tx_chan >= _get_num_radios()) { - break; - } - _tx_fe_map[tx_chan].db_fe_name = fe; - const fs_path fe_path(db_path / "tx_frontends" / fe); - const std::string conn = _tree->access<std::string>(fe_path / "connection").get(); - _tx_fe_map[tx_chan].core->set_mux(conn); - tx_chan++; - } - UHD_ASSERT_THROW(rx_chan or tx_chan); - - // Initialize the daughterboards now that frontend cores and connections exist - _db_manager->initialize_dboards(); - - // now that dboard is created -- register into rx antenna event - if (not _rx_fe_map.empty()) { - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_tree->exists(db_path / "rx_frontends" / _rx_fe_map[i].db_fe_name - / "antenna" / "value")) { - // We need a desired subscriber for antenna/value because the experts - // don't coerce that property. - _tree - ->access<std::string>(db_path / "rx_frontends" - / _rx_fe_map[i].db_fe_name / "antenna" - / "value") - .add_desired_subscriber(boost::bind( - &x300_radio_ctrl_impl::_update_atr_leds, this, _1, i)); - _update_atr_leds(_tree - ->access<std::string>(db_path / "rx_frontends" - / _rx_fe_map[i].db_fe_name - / "antenna" / "value") - .get(), - i); - } else { - _update_atr_leds("", i); // init anyway, even if never called - } - } - } - - // bind frontend corrections to the dboard freq props - const fs_path db_tx_fe_path = db_path / "tx_frontends"; - if (not _tx_fe_map.empty()) { - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_tree->exists( - db_tx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value")) { - _tree - ->access<double>( - db_tx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value") - .add_coerced_subscriber( - boost::bind(&x300_radio_ctrl_impl::set_tx_fe_corrections, - this, - db_path, - _root_path / "tx_fe_corrections" / _tx_fe_map[i].db_fe_name, - _1)); - } - } - } - const fs_path db_rx_fe_path = db_path / "rx_frontends"; - if (not _rx_fe_map.empty()) { - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_tree->exists( - db_rx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value")) { - _tree - ->access<double>( - db_rx_fe_path / _tx_fe_map[i].db_fe_name / "freq" / "value") - .add_coerced_subscriber( - boost::bind(&x300_radio_ctrl_impl::set_rx_fe_corrections, - this, - db_path, - _root_path / "rx_fe_corrections" / _tx_fe_map[i].db_fe_name, - _1)); - } - } - } - - //////////////////////////////////////////////////////////////// - // Set tick rate - //////////////////////////////////////////////////////////////// - const double tick_rate = _tree->access<double>("tick_rate").get(); - radio_ctrl_impl::set_rate(tick_rate); - - //////////////////////////////////////////////////////////////// - // Set gain groups - // Note: The actual gain control comes from the daughterboard drivers, thus, - // we need to call into the prop tree at the appropriate location in order - // to modify the gains. - //////////////////////////////////////////////////////////////// - // TX - for (size_t chan = 0; chan < _num_tx_channels; chan++) { - fs_path rf_gains_path(db_tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "gains"); - if (!_tree->exists(rf_gains_path)) { - continue; - } - - std::vector<std::string> gain_stages = _tree->list(rf_gains_path); - if (gain_stages.empty()) { - continue; - } - - // DAC does not have a gain path - auto gg = gain_group::make(); - for (const auto& name : gain_stages) { - gg->register_fcns(name, - make_gain_fcns_from_subtree(_tree->subtree(rf_gains_path / name)), - 1 /* high prio */); - } - _tx_gain_groups[chan] = gg; - } - // RX - for (size_t chan = 0; chan < _num_rx_channels; chan++) { - fs_path rf_gains_path(db_rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "gains"); - fs_path adc_gains_path("rx_codecs" / _radio_slot / "gains"); - - auto gg = gain_group::make(); - // ADC also has a gain path - for (const auto& name : _tree->list(adc_gains_path)) { - gg->register_fcns("ADC-" + name, - make_gain_fcns_from_subtree(_tree->subtree(adc_gains_path / name)), - 0 /* low prio */); - } - if (_tree->exists(rf_gains_path)) { - for (const auto& name : _tree->list(rf_gains_path)) { - gg->register_fcns(name, - make_gain_fcns_from_subtree(_tree->subtree(rf_gains_path / name)), - 1 /* high prio */); - } - } - _rx_gain_groups[chan] = gg; - } -} - -void x300_radio_ctrl_impl::set_rx_fe_corrections( - const fs_path& db_path, const fs_path& rx_fe_corr_path, const double lo_freq) -{ - if (not _ignore_cal_file) { - apply_rx_fe_corrections(_tree, db_path, rx_fe_corr_path, lo_freq); - } -} - -void x300_radio_ctrl_impl::set_tx_fe_corrections( - const fs_path& db_path, const fs_path& tx_fe_corr_path, const double lo_freq) -{ - if (not _ignore_cal_file) { - apply_tx_fe_corrections(_tree, db_path, tx_fe_corr_path, lo_freq); - } -} - -void x300_radio_ctrl_impl::reset_codec() -{ - if (_radio_type == PRIMARY) { // ADC/DAC reset lines only exist in Radio0 - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 1); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 0); - _regs->misc_outs_reg.flush(); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::ADC_RESET, 0); - _regs->misc_outs_reg.set(radio_regmap_t::misc_outs_reg_t::DAC_RESET_N, 1); - _regs->misc_outs_reg.flush(); - } - UHD_ASSERT_THROW(bool(_adc)); - UHD_ASSERT_THROW(bool(_dac)); - _adc->reset(); - _dac->reset(); -} - -void x300_radio_ctrl_impl::self_test_adc(uint32_t ramp_time_ms) -{ - // Bypass all front-end corrections - for (size_t i = 0; i < _get_num_radios(); i++) { - _rx_fe_map[i].core->bypass_all(true); - } - - // Test basic patterns - _adc->set_test_word("ones", "ones"); - _check_adc(0xfffcfffc); - _adc->set_test_word("zeros", "zeros"); - _check_adc(0x00000000); - _adc->set_test_word("ones", "zeros"); - _check_adc(0xfffc0000); - _adc->set_test_word("zeros", "ones"); - _check_adc(0x0000fffc); - for (size_t k = 0; k < 14; k++) { - _adc->set_test_word("zeros", "custom", 1 << k); - _check_adc(1 << (k + 2)); - } - for (size_t k = 0; k < 14; k++) { - _adc->set_test_word("custom", "zeros", 1 << k); - _check_adc(1 << (k + 18)); - } - - // Turn on ramp pattern test - _adc->set_test_word("ramp", "ramp"); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - // Sleep added for SPI transactions to finish and ramp to start before checker is - // enabled. - std::this_thread::sleep_for(std::chrono::microseconds(1000)); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - - std::this_thread::sleep_for(std::chrono::milliseconds(ramp_time_ms)); - _regs->misc_ins_reg.refresh(); - - std::string i_status, q_status; - if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_LOCKED)) - if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_ERROR)) - i_status = "Bit Errors!"; - else - i_status = "Good"; - else - i_status = "Not Locked!"; - - if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_LOCKED)) - if (_regs->misc_ins_reg.get(radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_ERROR)) - q_status = "Bit Errors!"; - else - q_status = "Good"; - else - q_status = "Not Locked!"; - - // Return to normal mode - _adc->set_test_word("normal", "normal"); - - if ((i_status != "Good") or (q_status != "Good")) { - throw uhd::runtime_error( - (boost::format( - "ADC self-test failed for %s. Ramp checker status: {ADC_A=%s, ADC_B=%s}") - % unique_id() % i_status % q_status) - .str()); - } - - // Restore front-end corrections - for (size_t i = 0; i < _get_num_radios(); i++) { - _rx_fe_map[i].core->bypass_all(false); - } -} - -void x300_radio_ctrl_impl::extended_adc_test( - const std::vector<x300_radio_ctrl_impl::sptr>& radios, double duration_s) -{ - static const size_t SECS_PER_ITER = 5; - UHD_LOGGER_INFO("X300 RADIO") - << boost::format( - "Running Extended ADC Self-Test (Duration=%.0fs, %ds/iteration)...") - % duration_s % SECS_PER_ITER; - - size_t num_iters = static_cast<size_t>(ceil(duration_s / SECS_PER_ITER)); - size_t num_failures = 0; - for (size_t iter = 0; iter < num_iters; iter++) { - // Run self-test - UHD_LOGGER_INFO("X300 RADIO") - << boost::format("Extended ADC Self-Test Iteration %06d... ") % (iter + 1); - try { - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->self_test_adc((SECS_PER_ITER * 1000) / radios.size()); - } - UHD_LOGGER_INFO("X300 RADIO") - << boost::format("Extended ADC Self-Test Iteration %06d passed ") - % (iter + 1); - } catch (std::exception& e) { - num_failures++; - UHD_LOGGER_ERROR("X300 RADIO") << e.what(); - } - } - if (num_failures == 0) { - UHD_LOGGER_INFO("X300 RADIO") << "Extended ADC Self-Test PASSED"; - } else { - throw uhd::runtime_error( - (boost::format("Extended ADC Self-Test FAILED!!! (%d/%d failures)\n") - % num_failures % num_iters) - .str()); - } -} - -void x300_radio_ctrl_impl::synchronize_dacs( - const std::vector<x300_radio_ctrl_impl::sptr>& radios) -{ - if (radios.size() < 2) - return; // Nothing to synchronize - - //**PRECONDITION** - // This function assumes that all the VITA times in "radios" are synchronized - // to a common reference. Currently, this function is called in get_tx_stream - // which also has the same precondition. - - // Get a rough estimate of the cumulative command latency - boost::posix_time::ptime t_start = boost::posix_time::microsec_clock::local_time(); - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->user_reg_read64( - regs::RB_TIME_NOW); // Discard value. We are just timing the call - } - boost::posix_time::time_duration t_elapsed = - boost::posix_time::microsec_clock::local_time() - t_start; - - // Add 100% of headroom + uncertainty to the command time - uint64_t t_sync_us = - (t_elapsed.total_microseconds() * 2) + 16000 /*Scheduler latency*/; - - std::string err_str; - // Try to sync 3 times before giving up - for (size_t attempt = 0; attempt < 3; attempt++) { - try { - // Reinitialize and resync all DACs - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->_dac->sync(); - } - - // Set tick rate and make sure FRAMEP/N is 0 - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->set_command_tick_rate( - radios[i]->_radio_clk_rate, IO_MASTER_RADIO); - radios[i]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0); - } - - // Pick radios[0] as the time reference. - uhd::time_spec_t sync_time = radios[0]->_time64->get_time_now() - + uhd::time_spec_t(((double)t_sync_us) / 1e6); - - // Send the sync command - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->set_command_time(sync_time, IO_MASTER_RADIO); - // Arm FRAMEP/N sync pulse by asserting a rising edge - radios[i]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 1); - } - - // Reset FRAMEP/N to 0 after 2 clock cycles - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->set_command_time( - sync_time + (2.0 / radios[i]->_radio_clk_rate), IO_MASTER_RADIO); - radios[i]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::DAC_SYNC, 0); - radios[i]->set_command_time(uhd::time_spec_t(0.0), IO_MASTER_RADIO); - } - - // Wait and check status - std::this_thread::sleep_for(std::chrono::microseconds(t_sync_us)); - for (size_t i = 0; i < radios.size(); i++) { - radios[i]->_dac->verify_sync(); - } - - return; - } catch (const uhd::runtime_error& e) { - err_str = e.what(); - UHD_LOGGER_TRACE("X300 RADIO") << "Retrying DAC synchronization: " << err_str; - } - } - throw uhd::runtime_error(err_str); -} - -double x300_radio_ctrl_impl::self_cal_adc_xfer_delay( - const std::vector<x300_radio_ctrl_impl::sptr>& radios, - x300_clock_ctrl::sptr clock, - boost::function<void(double)> wait_for_clk_locked, - bool apply_delay) -{ - UHD_LOGGER_INFO("X300 RADIO") << "Running ADC transfer delay self-cal: "; - - // Effective resolution of the self-cal. - static const size_t NUM_DELAY_STEPS = 100; - - double master_clk_period = (1.0e9 / clock->get_master_clock_rate()); // in ns - double delay_start = 0.0; - double delay_range = 2 * master_clk_period; - double delay_incr = delay_range / NUM_DELAY_STEPS; - - double cached_clk_delay = clock->get_clock_delay(X300_CLOCK_WHICH_ADC0); - double fpga_clk_delay = clock->get_clock_delay(X300_CLOCK_WHICH_FPGA); - - // Iterate through several values of delays and measure ADC data integrity - std::vector<std::pair<double, bool>> results; - for (size_t i = 0; i < NUM_DELAY_STEPS; i++) { - // Delay the ADC clock (will set both Ch0 and Ch1 delays) - double delay = - clock->set_clock_delay(X300_CLOCK_WHICH_ADC0, delay_incr * i + delay_start); - wait_for_clk_locked(0.1); - - uint32_t err_code = 0; - for (size_t r = 0; r < radios.size(); r++) { - // Test each channel (I and Q) individually so as to not accidentally trigger - // on the data from the other channel if there is a swap - - // -- Test I Channel -- - // Put ADC in ramp test mode. Tie the other channel to all ones. - radios[r]->_adc->set_test_word("ramp", "ones"); - // Turn on the pattern checker in the FPGA. It will lock when it sees a zero - // and count deviations from the expected value - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - // 50ms @ 200MHz = 10 million samples - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - if (radios[r]->_regs->misc_ins_reg.read( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_LOCKED)) { - err_code += radios[r]->_regs->misc_ins_reg.get( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_I_ERROR); - } else { - err_code += 100; // Increment error code by 100 to indicate no lock - } - - // -- Test Q Channel -- - // Put ADC in ramp test mode. Tie the other channel to all ones. - radios[r]->_adc->set_test_word("ones", "ramp"); - // Turn on the pattern checker in the FPGA. It will lock when it sees a zero - // and count deviations from the expected value - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - // 50ms @ 200MHz = 10 million samples - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - if (radios[r]->_regs->misc_ins_reg.read( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_LOCKED)) { - err_code += radios[r]->_regs->misc_ins_reg.get( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER1_Q_ERROR); - } else { - err_code += 100; // Increment error code by 100 to indicate no lock - } - } - // UHD_LOGGER_INFO("X300 RADIO") << (boost::format("XferDelay=%fns, Error=%d") % - // delay % err_code); - results.push_back(std::pair<double, bool>(delay, err_code == 0)); - } - - // Calculate the valid window - int win_start_idx = -1, win_stop_idx = -1, cur_start_idx = -1, cur_stop_idx = -1; - for (size_t i = 0; i < results.size(); i++) { - std::pair<double, bool>& item = results[i]; - if (item.second) { // If data is stable - if (cur_start_idx == -1) { // This is the first window - cur_start_idx = i; - cur_stop_idx = i; - } else { // We are extending the window - cur_stop_idx = i; - } - } else { - if (cur_start_idx == -1) { // We haven't yet seen valid data - // Do nothing - } else if (win_start_idx == -1) { // We passed the first valid window - win_start_idx = cur_start_idx; - win_stop_idx = cur_stop_idx; - } else { // Update cached window if current window is larger - double cur_win_len = - results[cur_stop_idx].first - results[cur_start_idx].first; - double cached_win_len = - results[win_stop_idx].first - results[win_start_idx].first; - if (cur_win_len > cached_win_len) { - win_start_idx = cur_start_idx; - win_stop_idx = cur_stop_idx; - } - } - // Reset current window - cur_start_idx = -1; - cur_stop_idx = -1; - } - } - if (win_start_idx == -1) { - throw uhd::runtime_error( - "self_cal_adc_xfer_delay: Self calibration failed. Convergence error."); - } - - double win_center = - (results[win_stop_idx].first + results[win_start_idx].first) / 2.0; - double win_length = results[win_stop_idx].first - results[win_start_idx].first; - if (win_length < master_clk_period / 4) { - throw uhd::runtime_error( - "self_cal_adc_xfer_delay: Self calibration failed. Valid window too narrow."); - } - - // Cycle slip the relative delay by a clock cycle to prevent sample misalignment - // fpga_clk_delay > 0 and 0 < win_center < 2*(1/MCR) so one cycle slip is all we need - bool cycle_slip = (win_center - fpga_clk_delay >= master_clk_period); - if (cycle_slip) { - win_center -= master_clk_period; - } - - if (apply_delay) { - // Apply delay - win_center = clock->set_clock_delay( - X300_CLOCK_WHICH_ADC0, win_center); // Sets ADC0 and ADC1 - wait_for_clk_locked(0.1); - // Validate - for (size_t r = 0; r < radios.size(); r++) { - radios[r]->self_test_adc(2000); - } - } else { - // Restore delay - clock->set_clock_delay( - X300_CLOCK_WHICH_ADC0, cached_clk_delay); // Sets ADC0 and ADC1 - } - - // Teardown - for (size_t r = 0; r < radios.size(); r++) { - radios[r]->_adc->set_test_word("normal", "normal"); - radios[r]->_regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - } - UHD_LOGGER_INFO("X300 RADIO") - << (boost::format( - "ADC transfer delay self-cal done (FPGA->ADC=%.3fns%s, Window=%.3fns)") - % (win_center - fpga_clk_delay) % (cycle_slip ? " +cyc" : "") - % win_length); - - return win_center; -} -/**************************************************************************** - * Helpers - ***************************************************************************/ -void x300_radio_ctrl_impl::_update_atr_leds(const std::string& rx_ant, const size_t chan) -{ - // The "RX1" port is used by TwinRX and the "TX/RX" port is used by all - // other full-duplex dboards. We need to handle both here. - const bool is_txrx = (rx_ant == "TX/RX" or rx_ant == "RX1"); - const int TXRX_RX = (1 << 0); - const int TXRX_TX = (1 << 1); - const int RX2_RX = (1 << 2); - _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_IDLE, 0); - _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_RX_ONLY, is_txrx ? TXRX_RX : RX2_RX); - _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_TX_ONLY, TXRX_TX); - _leds.at(chan)->set_atr_reg(gpio_atr::ATR_REG_FULL_DUPLEX, RX2_RX | TXRX_TX); -} - -void x300_radio_ctrl_impl::_self_cal_adc_capture_delay(bool print_status) -{ - if (print_status) - UHD_LOGGER_INFO("X300 RADIO") << "Running ADC capture delay self-cal..."; - - static const uint32_t NUM_DELAY_STEPS = 32; // The IDELAYE2 element has 32 steps - static const uint32_t NUM_RETRIES = - 2; // Retry self-cal if it fails in warmup situations - static const int32_t MIN_WINDOW_LEN = 4; - - int32_t win_start = -1, win_stop = -1; - uint32_t iter = 0; - while (iter++ < NUM_RETRIES) { - for (uint32_t dly_tap = 0; dly_tap < NUM_DELAY_STEPS; dly_tap++) { - // Apply delay - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_VAL, dly_tap); - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 1); - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 0); - - uint32_t err_code = 0; - - // -- Test I Channel -- - // Put ADC in ramp test mode. Tie the other channel to all ones. - _adc->set_test_word("ramp", "ones"); - // Turn on the pattern checker in the FPGA. It will lock when it sees a zero - // and count deviations from the expected value - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - // 5ms @ 200MHz = 1 million samples - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - if (_regs->misc_ins_reg.read( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_I_LOCKED)) { - err_code += _regs->misc_ins_reg.get( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_I_ERROR); - } else { - err_code += 100; // Increment error code by 100 to indicate no lock - } - - // -- Test Q Channel -- - // Put ADC in ramp test mode. Tie the other channel to all ones. - _adc->set_test_word("ones", "ramp"); - // Turn on the pattern checker in the FPGA. It will lock when it sees a zero - // and count deviations from the expected value - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 1); - // 5ms @ 200MHz = 1 million samples - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - if (_regs->misc_ins_reg.read( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_Q_LOCKED)) { - err_code += _regs->misc_ins_reg.get( - radio_regmap_t::misc_ins_reg_t::ADC_CHECKER0_Q_ERROR); - } else { - err_code += 100; // Increment error code by 100 to indicate no lock - } - - if (err_code == 0) { - if (win_start == -1) { // This is the first window - win_start = dly_tap; - win_stop = dly_tap; - } else { // We are extending the window - win_stop = dly_tap; - } - } else { - if (win_start != -1) { // A valid window turned invalid - if (win_stop - win_start >= MIN_WINDOW_LEN) { - break; // Valid window found - } else { - win_start = -1; // Reset window - } - } - } - // UHD_LOGGER_INFO("X300 RADIO") << (boost::format("CapTap=%d, Error=%d") % - // dly_tap % err_code); - } - - // Retry the self-cal if it fails - if ((win_start == -1 || (win_stop - win_start) < MIN_WINDOW_LEN) - && iter < NUM_RETRIES /*not last iteration*/) { - win_start = -1; - win_stop = -1; - std::this_thread::sleep_for(std::chrono::milliseconds(2000)); - } else { - break; - } - } - _adc->set_test_word("normal", "normal"); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_CHECKER_ENABLED, 0); - - if (win_start == -1) { - throw uhd::runtime_error( - "self_cal_adc_capture_delay: Self calibration failed. Convergence error."); - } - - if (win_stop - win_start < MIN_WINDOW_LEN) { - throw uhd::runtime_error("self_cal_adc_capture_delay: Self calibration failed. " - "Valid window too narrow."); - } - - uint32_t ideal_tap = (win_stop + win_start) / 2; - _regs->misc_outs_reg.write( - radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_VAL, ideal_tap); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 1); - _regs->misc_outs_reg.write(radio_regmap_t::misc_outs_reg_t::ADC_DATA_DLY_STB, 0); - - if (print_status) { - double tap_delay = (1.0e12 / _radio_clk_rate) / (2 * 32); // in ps - UHD_LOGGER_INFO("X300 RADIO") - << boost::format("ADC capture delay self-cal done (Tap=%d, Window=%d, " - "TapDelay=%.3fps, Iter=%d)") - % ideal_tap % (win_stop - win_start) % tap_delay % iter; - } -} - -void x300_radio_ctrl_impl::_check_adc(const uint32_t val) -{ - // Wait for previous control transaction to flush - user_reg_read64(regs::RB_TEST); - // Wait for ADC test pattern to propagate - std::this_thread::sleep_for(std::chrono::microseconds(5)); - // Read value of RX readback register and verify - uint32_t adc_rb = static_cast<uint32_t>(user_reg_read64(regs::RB_TEST) >> 32); - adc_rb ^= 0xfffc0000; // adapt for I inversion in FPGA - if (val != adc_rb) { - throw uhd::runtime_error( - (boost::format("ADC self-test failed for %s. (Exp=0x%x, Got=0x%x)") - % unique_id() % val % adc_rb) - .str()); - } -} - -void x300_radio_ctrl_impl::_set_db_eeprom( - i2c_iface::sptr i2c, const size_t addr, const uhd::usrp::dboard_eeprom_t& db_eeprom) -{ - db_eeprom.store(*i2c, addr); - _db_eeproms[addr] = db_eeprom; -} - -void x300_radio_ctrl_impl::_set_command_time(const time_spec_t& spec, const size_t port) -{ - set_fe_cmd_time(spec, port); -} -/**************************************************************************** - * Helpers - ***************************************************************************/ -bool x300_radio_ctrl_impl::check_radio_config() -{ - UHD_RFNOC_BLOCK_TRACE() << "x300_radio_ctrl_impl::check_radio_config() "; - const fs_path rx_fe_path = fs_path("dboards" / _radio_slot / "rx_frontends"); - for (size_t chan = 0; chan < _num_rx_channels; chan++) { - if (_tree->exists(rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "enabled")) { - const bool chan_active = _is_streamer_active(uhd::RX_DIRECTION, chan); - if (chan_active) { - _tree - ->access<bool>( - rx_fe_path / _rx_fe_map.at(chan).db_fe_name / "enabled") - .set(chan_active); - } - } - } - - const fs_path tx_fe_path = fs_path("dboards" / _radio_slot / "tx_frontends"); - for (size_t chan = 0; chan < _num_tx_channels; chan++) { - if (_tree->exists(tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "enabled")) { - const bool chan_active = _is_streamer_active(uhd::TX_DIRECTION, chan); - if (chan_active) { - _tree - ->access<bool>( - tx_fe_path / _tx_fe_map.at(chan).db_fe_name / "enabled") - .set(chan_active); - } - } - } - - return true; -} - -/**************************************************************************** - * Register block - ***************************************************************************/ -UHD_RFNOC_BLOCK_REGISTER(x300_radio_ctrl, "X300Radio"); diff --git a/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp b/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp deleted file mode 100644 index 63aac876d..000000000 --- a/host/lib/usrp/x300/x300_radio_ctrl_impl.hpp +++ /dev/null @@ -1,246 +0,0 @@ -// -// Copyright 2015-2016 Ettus Research -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP -#define INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP - -#include "x300_adc_ctrl.hpp" -#include "x300_clock_ctrl.hpp" -#include "x300_dac_ctrl.hpp" -#include "x300_regs.hpp" -#include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/usrp/dboard_manager.hpp> -#include <uhd/usrp/gpio_defs.hpp> -#include <uhd/utils/gain_group.hpp> -#include <uhdlib/rfnoc/radio_ctrl_impl.hpp> -#include <uhdlib/usrp/cores/rx_frontend_core_3000.hpp> -#include <uhdlib/usrp/cores/spi_core_3000.hpp> -#include <uhdlib/usrp/cores/tx_frontend_core_200.hpp> -#include <unordered_map> - -namespace uhd { namespace rfnoc { - -/*! \brief Provide access to an X300 radio. - */ -class x300_radio_ctrl_impl : public radio_ctrl_impl -{ -public: - typedef boost::shared_ptr<x300_radio_ctrl_impl> sptr; - - /************************************************************************ - * Structors - ***********************************************************************/ - UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(x300_radio_ctrl) - virtual ~x300_radio_ctrl_impl(); - - /************************************************************************ - * API calls - ***********************************************************************/ - double set_rate(double rate); - - void set_tx_antenna(const std::string& ant, const size_t chan); - void set_rx_antenna(const std::string& ant, const size_t chan); - std::string get_tx_antenna(const size_t chan); - std::string get_rx_antenna(const size_t chan); - - double set_tx_frequency(const double freq, const size_t chan); - double set_rx_frequency(const double freq, const size_t chan); - double set_rx_bandwidth(const double bandwidth, const size_t chan); - double get_tx_frequency(const size_t chan); - double get_rx_frequency(const size_t chan); - double get_rx_bandwidth(const size_t chan); - - double set_tx_gain(const double gain, const size_t chan); - double set_rx_gain(const double gain, const size_t chan); - double get_rx_gain(const size_t chan); - - std::vector<std::string> get_rx_lo_names(const size_t chan); - std::vector<std::string> get_rx_lo_sources( - const std::string& name, const size_t chan); - freq_range_t get_rx_lo_freq_range(const std::string& name, const size_t chan); - - void set_rx_lo_source( - const std::string& src, const std::string& name, const size_t chan); - const std::string get_rx_lo_source(const std::string& name, const size_t chan); - - void set_rx_lo_export_enabled( - bool enabled, const std::string& name, const size_t chan); - bool get_rx_lo_export_enabled(const std::string& name, const size_t chan); - - double set_rx_lo_freq(double freq, const std::string& name, const size_t chan); - double get_rx_lo_freq(const std::string& name, const size_t chan); - - size_t get_chan_from_dboard_fe(const std::string& fe, const direction_t dir); - std::string get_dboard_fe_from_chan(const size_t chan, const direction_t dir); - - std::vector<std::string> get_gpio_banks() const; - void set_gpio_attr(const std::string& bank, - const std::string& attr, - const uint32_t value, - const uint32_t mask); - uint32_t get_gpio_attr(const std::string& bank, const std::string& attr); - - double get_output_samp_rate(size_t port); - - /************************************************************************ - * Hardware setup and control - ***********************************************************************/ - /*! Set up the radio. No API calls may be made before this one. - */ - void setup_radio(uhd::i2c_iface::sptr zpu_i2c, - x300_clock_ctrl::sptr clock, - bool ignore_cal_file, - bool verbose); - - void reset_codec(); - - void self_test_adc(uint32_t ramp_time_ms = 100); - - static void extended_adc_test( - const std::vector<x300_radio_ctrl_impl::sptr>&, double duration_s); - - static void synchronize_dacs(const std::vector<x300_radio_ctrl_impl::sptr>& radios); - - static double self_cal_adc_xfer_delay( - const std::vector<x300_radio_ctrl_impl::sptr>& radios, - x300_clock_ctrl::sptr clock, - boost::function<void(double)> wait_for_clk_locked, - bool apply_delay); - -protected: - virtual bool check_radio_config(); - -private: - class radio_regmap_t : public uhd::soft_regmap_t - { - public: - typedef boost::shared_ptr<radio_regmap_t> sptr; - class misc_outs_reg_t : public uhd::soft_reg32_wo_t - { - public: - UHD_DEFINE_SOFT_REG_FIELD(DAC_ENABLED, /*width*/ 1, /*shift*/ 0); //[0] - UHD_DEFINE_SOFT_REG_FIELD(DAC_RESET_N, /*width*/ 1, /*shift*/ 1); //[1] - UHD_DEFINE_SOFT_REG_FIELD(ADC_RESET, /*width*/ 1, /*shift*/ 2); //[2] - UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_STB, /*width*/ 1, /*shift*/ 3); //[3] - UHD_DEFINE_SOFT_REG_FIELD(ADC_DATA_DLY_VAL, /*width*/ 5, /*shift*/ 4); //[8:4] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER_ENABLED, /*width*/ 1, /*shift*/ 9); //[9] - UHD_DEFINE_SOFT_REG_FIELD(DAC_SYNC, /*width*/ 1, /*shift*/ 10); //[10] - - misc_outs_reg_t() : uhd::soft_reg32_wo_t(regs::sr_addr(regs::MISC_OUTS)) - { - // Initial values - set(DAC_ENABLED, 0); - set(DAC_RESET_N, 0); - set(ADC_RESET, 0); - set(ADC_DATA_DLY_STB, 0); - set(ADC_DATA_DLY_VAL, 16); - set(ADC_CHECKER_ENABLED, 0); - set(DAC_SYNC, 0); - } - } misc_outs_reg; - - class misc_ins_reg_t : public uhd::soft_reg64_ro_t - { - public: - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER0_Q_LOCKED, /*width*/ 1, /*shift*/ 32); //[0] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER0_I_LOCKED, /*width*/ 1, /*shift*/ 33); //[1] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER1_Q_LOCKED, /*width*/ 1, /*shift*/ 34); //[2] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER1_I_LOCKED, /*width*/ 1, /*shift*/ 35); //[3] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER0_Q_ERROR, /*width*/ 1, /*shift*/ 36); //[4] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER0_I_ERROR, /*width*/ 1, /*shift*/ 37); //[5] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER1_Q_ERROR, /*width*/ 1, /*shift*/ 38); //[6] - UHD_DEFINE_SOFT_REG_FIELD( - ADC_CHECKER1_I_ERROR, /*width*/ 1, /*shift*/ 39); //[7] - - misc_ins_reg_t() : uhd::soft_reg64_ro_t(regs::rb_addr(regs::RB_MISC_IO)) {} - } misc_ins_reg; - - radio_regmap_t(int radio_num) - : soft_regmap_t("radio" + std::to_string(radio_num) + "_regmap") - { - add_to_map(misc_outs_reg, "misc_outs_reg", PRIVATE); - add_to_map(misc_ins_reg, "misc_ins_reg", PRIVATE); - } - }; - - struct x300_regs - { - static const uint32_t TX_FE_BASE = 224; - static const uint32_t RX_FE_BASE = 232; - }; - - void _update_atr_leds(const std::string& rx_ant, const size_t chan); - - void _self_cal_adc_capture_delay(bool print_status); - - void _check_adc(const uint32_t val); - - void _set_db_eeprom( - uhd::i2c_iface::sptr i2c, const size_t, const uhd::usrp::dboard_eeprom_t&); - - void set_rx_fe_corrections(const uhd::fs_path& db_path, - const uhd::fs_path& rx_fe_corr_path, - const double lo_freq); - void set_tx_fe_corrections(const uhd::fs_path& db_path, - const uhd::fs_path& tx_fe_corr_path, - const double lo_freq); - - void _set_command_time(const uhd::time_spec_t& spec, const size_t port); - void set_fe_cmd_time(const time_spec_t& time, const size_t chan); - -private: // members - enum radio_connection_t { PRIMARY, SECONDARY }; - - radio_connection_t _radio_type; - std::string _radio_slot; - //! Radio clock rate is the rate at which the ADC and DAC are running at. - // Not necessarily this block's sampling rate (tick rate). - double _radio_clk_rate; - - radio_regmap_t::sptr _regs; - std::map<size_t, usrp::gpio_atr::gpio_atr_3000::sptr> _leds; - spi_core_3000::sptr _spi; - x300_adc_ctrl::sptr _adc; - x300_dac_ctrl::sptr _dac; - usrp::gpio_atr::gpio_atr_3000::sptr _fp_gpio; - - std::map<size_t, usrp::dboard_eeprom_t> _db_eeproms; - usrp::dboard_manager::sptr _db_manager; - - struct rx_fe_perif - { - std::string name; - std::string db_fe_name; - rx_frontend_core_3000::sptr core; - }; - struct tx_fe_perif - { - std::string name; - std::string db_fe_name; - tx_frontend_core_200::sptr core; - }; - - std::map<size_t, rx_fe_perif> _rx_fe_map; - std::map<size_t, tx_fe_perif> _tx_fe_map; - - bool _ignore_cal_file; - - std::unordered_map<size_t, uhd::gain_group::sptr> _tx_gain_groups; - std::unordered_map<size_t, uhd::gain_group::sptr> _rx_gain_groups; -}; /* class radio_ctrl_impl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_X300_RADIO_CTRL_IMPL_HPP */ |