diff options
author | Sugandha Gupta <sugandha.gupta@ettus.com> | 2019-01-25 11:34:47 -0800 |
---|---|---|
committer | Brent Stapleton <brent.stapleton@ettus.com> | 2019-05-01 15:17:23 -0700 |
commit | 178b35569b1a25180a80a23b945b10b04c9f10f5 (patch) | |
tree | 3adb6f78ebd148867a50526c60fe7bf9694a4a72 /host/lib/usrp | |
parent | 8a400f6a30942c9d6d3596f6989720eb4cff058b (diff) | |
download | uhd-178b35569b1a25180a80a23b945b10b04c9f10f5.tar.gz uhd-178b35569b1a25180a80a23b945b10b04c9f10f5.tar.bz2 uhd-178b35569b1a25180a80a23b945b10b04c9f10f5.zip |
e310/e320: Move E310 to MPM architecture and refactor
- Turns the E310 into an MPM device (like N3xx, E320)
- Factor out common code between E320 and E310, maximize sharing between
the two devices
- Remove all pre-MPM E310 code that is no longer needed
- Modify MPM to remove all existing overlays before applying new ones
(this is necessary to enable idle image mode for E310)
Co-authored-by: Virendra Kakade <virendra.kakade@ni.com>
Signed-off-by: Virendra Kakade <virendra.kakade@ni.com>
Diffstat (limited to 'host/lib/usrp')
50 files changed, 1486 insertions, 6131 deletions
diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index 7f457d66a..6df37c2cf 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -46,7 +46,6 @@ INCLUDE_SUBDIRECTORY(mpmd) INCLUDE_SUBDIRECTORY(usrp1) INCLUDE_SUBDIRECTORY(usrp2) INCLUDE_SUBDIRECTORY(b100) -INCLUDE_SUBDIRECTORY(e300) INCLUDE_SUBDIRECTORY(x300) INCLUDE_SUBDIRECTORY(b200) INCLUDE_SUBDIRECTORY(n230) diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index f0e10871e..e12519c36 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -1916,7 +1916,7 @@ double ad9361_device_t::set_clock_rate(const double req_rate) /* This function returns the RX / TX rate between AD9361 and the FPGA. */ -double ad9361_device_t::get_clock_rate() +double ad9361_device_t::get_clock_rate() const { return _baseband_bw; } diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index 57f71193f..96a105438 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -162,7 +162,7 @@ public: void set_io_iface(ad9361_io::sptr io_iface); /* Get the current clock rate. */ - double get_clock_rate(); + double get_clock_rate() const; /* This function sets the RX / TX rate between AD9361 and the FPGA, and * thus determines the interpolation / decimation required in the FPGA to diff --git a/host/lib/usrp/dboard/CMakeLists.txt b/host/lib/usrp/dboard/CMakeLists.txt index 5328fcc90..8ee79103f 100644 --- a/host/lib/usrp/dboard/CMakeLists.txt +++ b/host/lib/usrp/dboard/CMakeLists.txt @@ -31,12 +31,6 @@ if(ENABLE_X300 OR ENABLE_USRP1 OR ENABLE_USRP2 OR ENABLE_B100) ) endif(ENABLE_X300 OR ENABLE_USRP1 OR ENABLE_USRP2 OR ENABLE_B100) -if(ENABLE_E300) - LIBUHD_APPEND_SOURCES( - ${CMAKE_CURRENT_SOURCE_DIR}/db_e3x0.cpp - ) -endif(ENABLE_E300) - if(ENABLE_X300) LIBUHD_APPEND_SOURCES( ${CMAKE_CURRENT_SOURCE_DIR}/twinrx/twinrx_ctrl.cpp @@ -46,6 +40,9 @@ if(ENABLE_X300) ) endif(ENABLE_X300) +if(ENABLE_E300 OR ENABLE_E320) + INCLUDE_SUBDIRECTORY(e3xx) +endif(ENABLE_E300 OR ENABLE_E320) if(ENABLE_N300) INCLUDE_SUBDIRECTORY(magnesium) endif(ENABLE_N300) @@ -55,5 +52,3 @@ endif(ENABLE_N320) if(ENABLE_MPMD AND ENABLE_EISCAT) INCLUDE_SUBDIRECTORY(eiscat) endif(ENABLE_MPMD AND ENABLE_EISCAT) - -INCLUDE_SUBDIRECTORY(neon) diff --git a/host/lib/usrp/dboard/db_e3x0.cpp b/host/lib/usrp/dboard/db_e3x0.cpp deleted file mode 100644 index 2745ee3e8..000000000 --- a/host/lib/usrp/dboard/db_e3x0.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include <uhd/utils/static.hpp> -#include <uhd/usrp/dboard_base.hpp> -#include <uhd/usrp/dboard_manager.hpp> - -namespace uhd { namespace usrp { - -/*********************************************************************** - * The E310 dboard - * AD9361 Interface, thus two subdevs - **********************************************************************/ -class e310_dboard : public xcvr_dboard_base{ -public: - e310_dboard(ctor_args_t args) : xcvr_dboard_base(args) {} - - virtual ~e310_dboard(void) {} -}; - -/*********************************************************************** - * The E310 dboard - * AD9364 Interface, thus one subdev - **********************************************************************/ -class e300_dboard : public xcvr_dboard_base{ -public: - e300_dboard(ctor_args_t args) : xcvr_dboard_base(args) {} - - virtual ~e300_dboard(void) {} -}; - -/*********************************************************************** - * Register the E310 dboards - **********************************************************************/ -static dboard_base::sptr make_e310_dboard(dboard_base::ctor_args_t args){ - return dboard_base::sptr(new e310_dboard(args)); -} - -static dboard_base::sptr make_e300_dboard(dboard_base::ctor_args_t args){ - return dboard_base::sptr(new e300_dboard(args)); -} - -}} // namespace - -using namespace uhd::usrp; - -UHD_STATIC_BLOCK(reg_e3x0_dboards){ - dboard_manager::register_dboard(0x0110, &make_e310_dboard, "E310 MIMO XCVR"); - dboard_manager::register_dboard(0x0100, &make_e300_dboard, "E300 SISO XCVR"); -} diff --git a/host/lib/usrp/dboard/e3xx/CMakeLists.txt b/host/lib/usrp/dboard/e3xx/CMakeLists.txt new file mode 100644 index 000000000..36376cd88 --- /dev/null +++ b/host/lib/usrp/dboard/e3xx/CMakeLists.txt @@ -0,0 +1,31 @@ +# +# Copyright 2018 Ettus Research, a National Instruments Company +# +# SPDX-License-Identifier: GPL-3.0-or-later +# + +IF(ENABLE_E300 OR ENABLE_E320) + LIST(APPEND E3XX_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/e3xx_radio_ctrl_impl.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e3xx_radio_ctrl_init.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e3xx_ad9361_iface.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/e3xx_bands.cpp + ) + LIBUHD_APPEND_SOURCES(${E3XX_SOURCES}) +ENDIF(ENABLE_E300 OR ENABLE_E320) + +IF(ENABLE_E300) + MESSAGE(STATUS "E300 Enabled") + LIST(APPEND E300_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/e31x_radio_ctrl_impl.cpp + ) + LIBUHD_APPEND_SOURCES(${E300_SOURCES}) +ENDIF(ENABLE_E300) + +IF(ENABLE_E320) + MESSAGE(STATUS "E320 Enabled") + LIST(APPEND E320_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/e320_radio_ctrl_impl.cpp + ) + LIBUHD_APPEND_SOURCES(${E320_SOURCES}) +ENDIF(ENABLE_E320) diff --git a/host/lib/usrp/dboard/e3xx/e31x_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/e3xx/e31x_radio_ctrl_impl.cpp new file mode 100644 index 000000000..33565102c --- /dev/null +++ b/host/lib/usrp/dboard/e3xx/e31x_radio_ctrl_impl.cpp @@ -0,0 +1,302 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "e31x_radio_ctrl_impl.hpp" +#include "e31x_regs.hpp" + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::rfnoc; + +e31x_radio_ctrl_impl::e31x_radio_ctrl_impl( + const make_args_t &make_args +): block_ctrl_base(make_args) +{ + // Swap front ends for E310 + _fe_swap = true; +} + +e31x_radio_ctrl_impl::~e31x_radio_ctrl_impl() +{ + UHD_LOG_TRACE(unique_id(), "e31x_radio_ctrl_impl::dtor() "); +} + +/****************************************************************************** + * API Calls + *****************************************************************************/ +bool e31x_radio_ctrl_impl::check_radio_config() +{ + // mapping of frontend to radio perif index + static const size_t FE0 = 1; + static const size_t FE1 = 0; + const size_t num_rx = _is_streamer_active(RX_DIRECTION, FE0) + _is_streamer_active(RX_DIRECTION, FE1); + const size_t num_tx = _is_streamer_active(TX_DIRECTION, FE0) + _is_streamer_active(TX_DIRECTION, FE1); + + //setup the active chains in the codec + if ((num_rx + num_tx) == 0) { + // Ensure at least one RX chain is enabled so AD9361 outputs a sample clock + this->set_streaming_mode(true, false, true, false); + } else { + this->set_streaming_mode( + _is_streamer_active(TX_DIRECTION, FE0), + _is_streamer_active(TX_DIRECTION, FE1), + _is_streamer_active(RX_DIRECTION, FE0), + _is_streamer_active(RX_DIRECTION, FE1) + ); + } + return true; +} + +/* loopback_self_test checks the integrity of the FPGA->AD936x->FPGA sample interface. + The AD936x is put in loopback mode that sends the TX data unchanged to the RX side. + A test value is written to the codec_idle register in the TX side of the radio. + The readback register is then used to capture the values on the TX and RX sides + simultaneously for comparison. It is a reasonably effective test for AC timing + since I/Q Ch0/Ch1 alternate over the same wires. Note, however, that it uses + whatever timing is configured at the time the test is called rather than select + worst case conditions to stress the interface. + Note: This currently only tests 2R2T mode +*/ +void e31x_radio_ctrl_impl::loopback_self_test( + std::function<void(uint32_t)> poker_functor, std::function<uint64_t()> peeker_functor) +{ + // Save current rate before running this test + const double current_rate = this->get_rate(); + // Set 2R2T mode, stream on all channels + this->set_streaming_mode(true, false, true, false); + // Set maximum rate for 2R2T mode + this->set_rate(30.72e6); + // Put AD936x in loopback mode + _ad9361->data_port_loopback(true); + UHD_LOG_INFO(unique_id(), "Performing CODEC loopback test... "); + size_t hash = size_t(time(NULL)); + constexpr size_t loopback_count = 100; + + // Allow some time for AD936x to enter loopback mode. + // There is no clear statement in the documentation of how long it takes, + // but UG-570 does say to "allow six ADC_CLK/64 clock cycles of flush time" + // when leaving the TX or RX states. That works out to ~75us at the + // minimum clock rate of 5 MHz, which lines up with test results. + // Sleeping 1ms is far more than enough. + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + for (size_t i = 0; i < loopback_count; i++) { + // Create test word + boost::hash_combine(hash, i); + const uint32_t word32 = uint32_t(hash) & 0xfff0fff0; + // const uint32_t word32 = 0xCA00C100; + // Write test word to codec_idle idle register (on TX side) + poker_functor(word32); + + // Read back values - TX is lower 32-bits and RX is upper 32-bits + const uint64_t rb_word64 = peeker_functor(); + const uint32_t rb_tx = uint32_t(rb_word64 >> 32); + const uint32_t rb_rx = uint32_t(rb_word64 & 0xffffffff); + + // Compare TX and RX values to test word + bool test_fail = word32 != rb_tx or word32 != rb_rx; + if (test_fail) { + UHD_LOG_WARNING(unique_id(), + "CODEC loopback test failed! " + << boost::format("Expected: 0x%08X Received (TX/RX): 0x%08X/0x%08X") + % word32 % rb_tx % rb_rx); + throw uhd::runtime_error("CODEC loopback test failed."); + } + } + UHD_LOG_INFO(unique_id(), "CODEC loopback test passed"); + + // Zero out the idle data. + poker_functor(0); + + // Take AD936x out of loopback mode + _ad9361->data_port_loopback(false); + this->set_streaming_mode(true, false, true, false); + // Switch back to current rate + this->set_rate(current_rate); +} + + +uint32_t e31x_radio_ctrl_impl::get_tx_switches( + const size_t chan, + const double freq +) { + UHD_LOG_TRACE(unique_id(), + "Update all TX freq related switches. f=" << freq << " Hz, " + ); + + size_t fe_chan = _fe_swap ? (chan ? 0 : 1): chan; + + auto tx_sw1 = TX_SW1_LB_2750; // SW1 = 0 + auto vctxrx_sw = VCTXRX_SW_OFF; + auto tx_bias = (fe_chan == 0) ? TX1_BIAS_LB_ON: TX2_BIAS_LB_ON; + + const auto band = e3xx_radio_ctrl_impl::map_freq_to_tx_band(freq); + switch(band) { + case tx_band::LB_80: + tx_sw1 = TX_SW1_LB_80; + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_TX_LB: VCTXRX2_SW_TX_LB; + break; + case tx_band::LB_160: + tx_sw1 = TX_SW1_LB_160; + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_TX_LB: VCTXRX2_SW_TX_LB; + break; + case tx_band::LB_225: + tx_sw1 = TX_SW1_LB_225; + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_TX_LB: VCTXRX2_SW_TX_LB; + break; + case tx_band::LB_400: + tx_sw1 = TX_SW1_LB_400; + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_TX_LB: VCTXRX2_SW_TX_LB; + break; + case tx_band::LB_575: + tx_sw1 = TX_SW1_LB_575; + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_TX_LB: VCTXRX2_SW_TX_LB; + break; + case tx_band::LB_1000: + tx_sw1 = TX_SW1_LB_1000; + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_TX_LB: VCTXRX2_SW_TX_LB; + break; + case tx_band::LB_1700: + tx_sw1 = TX_SW1_LB_1700; + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_TX_LB: VCTXRX2_SW_TX_LB; + break; + case tx_band::LB_2750: + tx_sw1 = TX_SW1_LB_2750; + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_TX_LB: VCTXRX2_SW_TX_LB; + break; + case tx_band::HB: + tx_sw1 = TX_SW1_LB_80; + vctxrx_sw = VCTXRX_SW_TX_HB; + tx_bias = (fe_chan == 0) ? TX1_BIAS_HB_ON: TX2_BIAS_HB_ON; + break; + case tx_band::INVALID_BAND: + UHD_LOG_ERROR(unique_id(), + "Cannot map TX frequency to band: " << freq); + UHD_THROW_INVALID_CODE_PATH(); + break; + } + auto tx_regs = 0 | + vctxrx_sw << VCTXRX_SW_SHIFT | + tx_bias << TX_BIAS_SHIFT | + tx_sw1 << TX_SW1_SHIFT; + return tx_regs; +} + +uint32_t e31x_radio_ctrl_impl::get_rx_switches( + const size_t chan, + const double freq, + const std::string &ant +){ + UHD_LOG_TRACE(unique_id(), + "Update all RX freq related switches. f=" << freq << " Hz, " + ); + + size_t fe_chan = _fe_swap ? (chan ? 0 : 1): chan; + + // Default to OFF + auto rx_sw1 = RX_SW1_OFF; + auto rx_swc = RX_SWC_OFF; + auto rx_swb = RX_SWB_OFF; + auto vctxrx_sw = VCTXRX_SW_OFF; + auto vcrx_sw = VCRX_SW_LB; + if (ant == "TX/RX") { + vctxrx_sw = (fe_chan == 0) ? VCTXRX1_SW_RX: VCTXRX2_SW_RX; + } + + UHD_LOG_INFO(unique_id(), "RX freq = " << freq); + const auto band = e3xx_radio_ctrl_impl::map_freq_to_rx_band(freq); + UHD_LOG_INFO(unique_id(), "RX band = " << int(band)); + + switch(band) { + case rx_band::LB_B2: + rx_sw1 = RX_SW1_LB_B2; + rx_swc = RX_SWC_LB_B2; + rx_swb = RX_SWB_OFF; + break; + case rx_band::LB_B3: + rx_sw1 = RX_SW1_LB_B3; + rx_swc = RX_SWC_LB_B3; + rx_swb = RX_SWB_OFF; + break; + case rx_band::LB_B4: + rx_sw1 = RX_SW1_LB_B4; + rx_swc = RX_SWC_LB_B4; + rx_swb = RX_SWB_OFF; + break; + case rx_band::LB_B5: + rx_sw1 = RX_SW1_LB_B5; + rx_swc = RX_SWC_OFF; + rx_swb = RX_SWB_LB_B5; + break; + case rx_band::LB_B6: + rx_sw1 = RX_SW1_LB_B6; + rx_swc = RX_SWC_OFF; + rx_swb = RX_SWB_LB_B6; + break; + case rx_band::LB_B7: + rx_sw1 = RX_SW1_LB_B7; + rx_swc = RX_SWC_OFF; + rx_swb = RX_SWB_LB_B7; + break; + case rx_band::HB: + rx_sw1 = RX_SW1_OFF; + rx_swc = RX_SWC_OFF; + rx_swb = RX_SWB_OFF; + vcrx_sw = VCRX_SW_HB; + break; + case rx_band::INVALID_BAND: + UHD_LOG_ERROR(unique_id(), + "Cannot map RX frequency to band: " << freq); + UHD_THROW_INVALID_CODE_PATH(); + break; + } + UHD_LOG_INFO(unique_id(), "RX SW1 = " << rx_sw1); + UHD_LOG_INFO(unique_id(), "RX SWC = " << rx_swc); + UHD_LOG_INFO(unique_id(), "RX SWB = " << rx_swb); + UHD_LOG_INFO(unique_id(), "RX VCRX_SW = " << vcrx_sw); + UHD_LOG_INFO(unique_id(), "RX VCTXRX_SW = " << vctxrx_sw); + + auto rx_regs = 0 | + vcrx_sw << VCRX_SW_SHIFT | + vctxrx_sw << VCTXRX_SW_SHIFT | + rx_swc << RX_SWC_SHIFT | + rx_swb << RX_SWB_SHIFT | + rx_sw1 << RX_SW1_SHIFT; + return rx_regs; +} + +uint32_t e31x_radio_ctrl_impl::get_idle_switches() +{ + uint32_t idle_regs = VCRX_SW_OFF << VCRX_SW_SHIFT | + VCTXRX_SW_OFF << VCTXRX_SW_SHIFT | + TX_BIAS_OFF << TX_BIAS_SHIFT | + RX_SWC_OFF << RX_SWC_SHIFT | + RX_SWB_OFF << RX_SWB_SHIFT | + RX_SW1_OFF << RX_SW1_SHIFT | + TX_SW1_LB_2750 << TX_SW1_SHIFT; + return idle_regs; +} + +uint32_t e31x_radio_ctrl_impl::get_idle_led() +{ + return 0; +} + +uint32_t e31x_radio_ctrl_impl::get_rx_led() +{ + return 1 << LED_RX_RX_SHIFT; +} + +uint32_t e31x_radio_ctrl_impl::get_tx_led() +{ + return 1 << LED_TXRX_TX_SHIFT; +} + +uint32_t e31x_radio_ctrl_impl::get_txrx_led() +{ + return 1 << LED_TXRX_RX_SHIFT; +} +UHD_RFNOC_BLOCK_REGISTER(e31x_radio_ctrl, "E31XRadio"); diff --git a/host/lib/usrp/dboard/e3xx/e31x_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/e3xx/e31x_radio_ctrl_impl.hpp new file mode 100644 index 000000000..581a90c8e --- /dev/null +++ b/host/lib/usrp/dboard/e3xx/e31x_radio_ctrl_impl.hpp @@ -0,0 +1,144 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_LIBUHD_RFNOC_E31X_RADIO_CTRL_IMPL_HPP +#define INCLUDED_LIBUHD_RFNOC_E31X_RADIO_CTRL_IMPL_HPP + +#include "e3xx_constants.hpp" +#include "e3xx_radio_ctrl_impl.hpp" + +namespace uhd { + namespace rfnoc { + +/*! \brief Provide access to an E31X radio. + */ +class e31x_radio_ctrl_impl : public e3xx_radio_ctrl_impl +{ +public: + /************************************************************************ + * Structors + ***********************************************************************/ + e31x_radio_ctrl_impl( + const make_args_t &make_args + ); + virtual ~e31x_radio_ctrl_impl(); + +protected: + + /************************************************************************** + * ATR/ Switches Types + *************************************************************************/ + + enum tx_sw1_t { + TX_SW1_LB_80 = 7, + TX_SW1_LB_160 = 6, + TX_SW1_LB_225 = 5, + TX_SW1_LB_400 = 4, + TX_SW1_LB_575 = 3, + TX_SW1_LB_1000 = 2, + TX_SW1_LB_1700 = 1, + TX_SW1_LB_2750 = 0, + TX_SW1_HB_5850 = 7 + }; + + enum vctxrx_sw_t { + VCTXRX_SW_TX_HB = 3, + VCTXRX1_SW_TX_LB = 1, + VCTXRX1_SW_RX = 2, + VCTXRX2_SW_TX_LB = 2, + VCTXRX2_SW_RX = 1, + VCTXRX_SW_OFF = 0, + }; + + enum rx_sw1_t { + RX_SW1_LB_B2 = 4, + RX_SW1_LB_B3 = 2, + RX_SW1_LB_B4 = 0, + RX_SW1_LB_B5 = 1, + RX_SW1_LB_B6 = 3, + RX_SW1_LB_B7 = 5, + RX_SW1_OFF = 7 + }; + + enum rx_swc_t { + RX_SWC_LB_B2 = 2, + RX_SWC_LB_B3 = 3, + RX_SWC_LB_B4 = 1, + RX_SWC_OFF = 0 + }; + + enum rx_swb_t { + RX_SWB_LB_B5 = 2, + RX_SWB_LB_B6 = 3, + RX_SWB_LB_B7 = 1, + RX_SWB_OFF = 0 + }; + + enum vcrx_sw_t { + VCRX_SW_LB = 1, + VCRX_SW_HB = 2, + VCRX_SW_OFF = 0 //or 3 + }; + + // (TX_ENABLEB, TX_ENABLEA) + enum tx_bias_t { + TX1_BIAS_HB_ON = 1, + TX1_BIAS_LB_ON = 2, + TX2_BIAS_HB_ON = 1, + TX2_BIAS_LB_ON = 2, + TX_BIAS_OFF = 0 + }; + + /************************************************************************ + * API calls + ***********************************************************************/ + virtual bool check_radio_config(); + + const std::string get_default_timing_mode() + { + return TIMING_MODE_1R1T; + }; + + /*! Run a loopback self test. + * + * This will write data to the AD936x and read it back again. + * If this test fails, it generally means the interface is broken, + * so we assume it passes and throw otherwise. Running this requires + * a core that we can peek and poke the loopback values into. + * + * \param iface An interface to the associated radio control core + * \param iface The radio control core's address to write the loopback value + * \param iface The radio control core's readback address to read back the returned + * value + * + * \throws a uhd::runtime_error if the loopback value didn't match. + */ + void loopback_self_test(std::function<void(uint32_t)> poker_functor, + std::function<uint64_t()> peeker_functor); + + uint32_t get_rx_switches( + const size_t chan, + const double freq, + const std::string &ant + ); + + uint32_t get_tx_switches( + const size_t chan, + const double freq + ); + + uint32_t get_idle_switches(); + + uint32_t get_tx_led(); + uint32_t get_rx_led(); + uint32_t get_txrx_led(); + uint32_t get_idle_led(); +}; /* class radio_ctrl_impl */ + +}} /* namespace uhd::rfnoc */ + +#endif /* INCLUDED_LIBUHD_RFNOC_E31X_RADIO_CTRL_IMPL_HPP */ +// vim: sw=4 et: diff --git a/host/lib/usrp/dboard/e3xx/e31x_regs.hpp b/host/lib/usrp/dboard/e3xx/e31x_regs.hpp new file mode 100644 index 000000000..15ce90743 --- /dev/null +++ b/host/lib/usrp/dboard/e3xx/e31x_regs.hpp @@ -0,0 +1,26 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_E31X_REGS_HPP +#define INCLUDED_E31X_REGS_HPP + +#include <uhd/config.hpp> +#include <cstdint> + +static const uint32_t VCRX_SW_SHIFT = 14; +static const uint32_t VCTXRX_SW_SHIFT = 12; +static const uint32_t TX_BIAS_SHIFT = 10; +static const uint32_t RX_SWC_SHIFT = 8; +static const uint32_t RX_SWB_SHIFT = 6; +static const uint32_t RX_SW1_SHIFT = 3; +static const uint32_t TX_SW1_SHIFT = 0; + +static const uint32_t LED_RX_RX_SHIFT = 2; +static const uint32_t LED_TXRX_TX_SHIFT = 1; +static const uint32_t LED_TXRX_RX_SHIFT = 0; + +#endif /* INCLUDED_E31X_REGS_HPP */ + diff --git a/host/lib/usrp/dboard/e3xx/e320_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/e3xx/e320_radio_ctrl_impl.cpp new file mode 100644 index 000000000..c48cabc9c --- /dev/null +++ b/host/lib/usrp/dboard/e3xx/e320_radio_ctrl_impl.cpp @@ -0,0 +1,272 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "e320_radio_ctrl_impl.hpp" +#include "e320_regs.hpp" + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::rfnoc; + +e320_radio_ctrl_impl::e320_radio_ctrl_impl(const make_args_t& make_args) + : block_ctrl_base(make_args) +{ + UHD_LOG_TRACE(unique_id(), "Entering e320_radio_ctrl_impl ctor..."); + // Don't swap front ends for E320 + _fe_swap = false; +} + +e320_radio_ctrl_impl::~e320_radio_ctrl_impl() +{ + UHD_LOG_TRACE(unique_id(), "e320_radio_ctrl_impl::dtor() "); +} + +/****************************************************************************** + * API Calls + *****************************************************************************/ +bool e320_radio_ctrl_impl::check_radio_config() +{ + // mapping of frontend to radio perif index + static const size_t FE0 = 0; + static const size_t FE1 = 1; + const size_t num_rx = + _is_streamer_active(RX_DIRECTION, FE0) + _is_streamer_active(RX_DIRECTION, FE1); + const size_t num_tx = + _is_streamer_active(TX_DIRECTION, FE0) + _is_streamer_active(TX_DIRECTION, FE1); + + // setup the active chains in the codec + if ((num_rx + num_tx) == 0) { + // Ensure at least one RX chain is enabled so AD9361 outputs a sample clock + this->set_streaming_mode(true, false, true, false); + } else { + this->set_streaming_mode(_is_streamer_active(TX_DIRECTION, FE0), + _is_streamer_active(TX_DIRECTION, FE1), + _is_streamer_active(RX_DIRECTION, FE0), + _is_streamer_active(RX_DIRECTION, FE1)); + } + return true; +} + +/* loopback_self_test checks the integrity of the FPGA->AD936x->FPGA sample interface. + The AD936x is put in loopback mode that sends the TX data unchanged to the RX side. + A test value is written to the codec_idle register in the TX side of the radio. + The readback register is then used to capture the values on the TX and RX sides + simultaneously for comparison. It is a reasonably effective test for AC timing + since I/Q Ch0/Ch1 alternate over the same wires. Note, however, that it uses + whatever timing is configured at the time the test is called rather than select + worst case conditions to stress the interface. + Note: This currently only tests 2R2T mode +*/ +void e320_radio_ctrl_impl::loopback_self_test( + std::function<void(uint32_t)> poker_functor, std::function<uint64_t()> peeker_functor) +{ + // Save current rate before running this test + const double current_rate = this->get_rate(); + // Set 2R2T mode, stream on all channels + this->set_streaming_mode(true, true, true, true); + // Set maximum rate for 2R2T mode + this->set_rate(30.72e6); + // Put AD936x in loopback mode + _ad9361->data_port_loopback(true); + UHD_LOG_INFO(unique_id(), "Performing CODEC loopback test... "); + size_t hash = size_t(time(NULL)); + constexpr size_t loopback_count = 100; + + // Allow some time for AD936x to enter loopback mode. + // There is no clear statement in the documentation of how long it takes, + // but UG-570 does say to "allow six ADC_CLK/64 clock cycles of flush time" + // when leaving the TX or RX states. That works out to ~75us at the + // minimum clock rate of 5 MHz, which lines up with test results. + // Sleeping 1ms is far more than enough. + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + for (size_t i = 0; i < loopback_count; i++) { + // Create test word + boost::hash_combine(hash, i); + const uint32_t word32 = uint32_t(hash) & 0xfff0fff0; + // const uint32_t word32 = 0xCA00C100; + // Write test word to codec_idle idle register (on TX side) + poker_functor(word32); + + // Read back values - TX is lower 32-bits and RX is upper 32-bits + const uint64_t rb_word64 = peeker_functor(); + const uint32_t rb_tx = uint32_t(rb_word64 >> 32); + const uint32_t rb_rx = uint32_t(rb_word64 & 0xffffffff); + + // Compare TX and RX values to test word + bool test_fail = word32 != rb_tx or word32 != rb_rx; + if (test_fail) { + UHD_LOG_WARNING(unique_id(), + "CODEC loopback test failed! " + << boost::format("Expected: 0x%08X Received (TX/RX): 0x%08X/0x%08X") + % word32 % rb_tx % rb_rx); + throw uhd::runtime_error("CODEC loopback test failed."); + } + } + UHD_LOG_INFO(unique_id(), "CODEC loopback test passed"); + + // Zero out the idle data. + poker_functor(0); + + // Take AD936x out of loopback mode + _ad9361->data_port_loopback(false); + this->set_streaming_mode(true, false, true, false); + // Switch back to current rate + this->set_rate(current_rate); +} + +uint32_t e320_radio_ctrl_impl::get_tx_switches(const size_t chan, const double freq) +{ + UHD_LOG_TRACE( + unique_id(), "Update all TX freq related switches. f=" << freq << " Hz, "); + auto tx_sw1 = TX_SW1_LB_160; + auto tx_sw2 = TX_SW2_LB_160; + auto trx_sw = (chan == 0) ? TRX1_SW_TX_LB : TRX2_SW_TX_LB; + auto tx_amp = TX_AMP_LF_ON; + + const auto band = e3xx_radio_ctrl_impl::map_freq_to_tx_band(freq); + switch (band) { + case tx_band::LB_80: + tx_sw1 = TX_SW1_LB_80; + tx_sw2 = TX_SW2_LB_80; + break; + case tx_band::LB_160: + tx_sw1 = TX_SW1_LB_160; + tx_sw2 = TX_SW2_LB_160; + break; + case tx_band::LB_225: + tx_sw1 = TX_SW1_LB_225; + tx_sw2 = TX_SW2_LB_225; + break; + case tx_band::LB_400: + tx_sw1 = TX_SW1_LB_400; + tx_sw2 = TX_SW2_LB_400; + break; + case tx_band::LB_575: + tx_sw1 = TX_SW1_LB_575; + tx_sw2 = TX_SW2_LB_575; + break; + case tx_band::LB_1000: + tx_sw1 = TX_SW1_LB_1000; + tx_sw2 = TX_SW2_LB_1000; + break; + case tx_band::LB_1700: + tx_sw1 = TX_SW1_LB_1700; + tx_sw2 = TX_SW2_LB_1700; + break; + case tx_band::LB_2750: + tx_sw1 = TX_SW1_LB_2750; + tx_sw2 = TX_SW2_LB_2750; + break; + case tx_band::HB: + trx_sw = (chan == 0) ? TRX1_SW_TX_HB : TRX2_SW_TX_HB; + tx_amp = TX_AMP_HF_ON; + break; + case tx_band::INVALID_BAND: + UHD_LOG_ERROR(unique_id(), "Cannot map TX frequency to band: " << freq); + UHD_THROW_INVALID_CODE_PATH(); + break; + } + + auto tx_regs = tx_amp << TX_AMP_SHIFT | trx_sw << TRX_SW_SHIFT + | tx_sw2 << TX_SW2_SHIFT | tx_sw1 << TX_SW1_SHIFT; + return tx_regs; +} + +uint32_t e320_radio_ctrl_impl::get_rx_switches( + const size_t chan, const double freq, const std::string& ant) +{ + UHD_LOG_TRACE( + unique_id(), "Update all RX freq related switches. f=" << freq << " Hz, "); + // Default to OFF + auto rx_sw1 = RX_SW1_OFF; + auto rx_sw2 = RX_SW2_OFF; + auto rx_sw3 = RX_SW3_OFF; + auto trx_sw = (chan == 0) ? TRX1_SW_RX : TRX2_SW_RX; + if (ant == "TX/RX") { + rx_sw3 = RX_SW3_HBRX_LBTRX; + trx_sw = (chan == 0) ? TRX1_SW_RX : TRX2_SW_RX; + } else if (ant == "RX2") { + rx_sw3 = RX_SW3_HBTRX_LBRX; + // Set TRX switch to TX when receiving on RX2 + trx_sw = TRX1_SW_TX_HB; + } + + const auto band = e3xx_radio_ctrl_impl::map_freq_to_rx_band(freq); + switch (band) { + case rx_band::LB_B2: + rx_sw1 = RX_SW1_LB_B2; + rx_sw2 = RX_SW2_LB_B2; + break; + case rx_band::LB_B3: + rx_sw1 = RX_SW1_LB_B3; + rx_sw2 = RX_SW2_LB_B3; + break; + case rx_band::LB_B4: + rx_sw1 = RX_SW1_LB_B4; + rx_sw2 = RX_SW2_LB_B4; + break; + case rx_band::LB_B5: + rx_sw1 = RX_SW1_LB_B5; + rx_sw2 = RX_SW2_LB_B5; + break; + case rx_band::LB_B6: + rx_sw1 = RX_SW1_LB_B6; + rx_sw2 = RX_SW2_LB_B6; + break; + case rx_band::LB_B7: + rx_sw1 = RX_SW1_LB_B7; + rx_sw2 = RX_SW2_LB_B7; + break; + case rx_band::HB: + rx_sw1 = RX_SW1_OFF; + rx_sw2 = RX_SW2_OFF; + if (ant == "TX/RX") { + rx_sw3 = RX_SW3_HBTRX_LBRX; + } else if (ant == "RX2") { + rx_sw3 = RX_SW3_HBRX_LBTRX; + } + break; + case rx_band::INVALID_BAND: + UHD_LOG_ERROR(unique_id(), "Cannot map RX frequency to band: " << freq); + UHD_THROW_INVALID_CODE_PATH(); + break; + } + + auto rx_regs = trx_sw << TRX_SW_SHIFT | rx_sw3 << RX_SW3_SHIFT + | rx_sw2 << RX_SW2_SHIFT | rx_sw1 << RX_SW1_SHIFT; + return rx_regs; +} + +uint32_t e320_radio_ctrl_impl::get_idle_switches() +{ + uint32_t idle_regs = TX_AMP_OFF << TX_AMP_SHIFT | TRX1_SW_TX_HB << TRX_SW_SHIFT + | TX_SW2_LB_80 << TX_SW2_SHIFT | TX_SW1_LB_80 << TX_SW1_SHIFT + | RX_SW3_OFF << RX_SW3_SHIFT | RX_SW2_OFF << RX_SW2_SHIFT + | RX_SW1_OFF << RX_SW1_SHIFT; + return idle_regs; +} + +uint32_t e320_radio_ctrl_impl::get_idle_led() +{ + return 0; +} + +uint32_t e320_radio_ctrl_impl::get_rx_led() +{ + return 1 << TRX_LED_GRN_SHIFT; +} + +uint32_t e320_radio_ctrl_impl::get_tx_led() +{ + return 1 << TX_LED_RED_SHIFT; +} + +uint32_t e320_radio_ctrl_impl::get_txrx_led() +{ + return 1 << RX_LED_GRN_SHIFT; +} +UHD_RFNOC_BLOCK_REGISTER(e320_radio_ctrl, "NeonRadio"); diff --git a/host/lib/usrp/dboard/e3xx/e320_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/e3xx/e320_radio_ctrl_impl.hpp new file mode 100644 index 000000000..7f75cadc7 --- /dev/null +++ b/host/lib/usrp/dboard/e3xx/e320_radio_ctrl_impl.hpp @@ -0,0 +1,134 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_LIBUHD_RFNOC_E320_RADIO_CTRL_IMPL_HPP +# define INCLUDED_LIBUHD_RFNOC_E320_RADIO_CTRL_IMPL_HPP + +# include "e3xx_constants.hpp" +# include "e3xx_radio_ctrl_impl.hpp" + +namespace uhd { namespace rfnoc { + +/*! \brief Provide access to an E320 radio. + */ +class e320_radio_ctrl_impl : public e3xx_radio_ctrl_impl +{ +public: + /************************************************************************ + * Structors + ***********************************************************************/ + e320_radio_ctrl_impl(const make_args_t& make_args); + virtual ~e320_radio_ctrl_impl(); + +protected: + /************************************************************************** + * ATR/ Switches Types + *************************************************************************/ + + enum tx_sw1_t { + TX_SW1_LB_80 = 3, + TX_SW1_LB_160 = 7, + TX_SW1_LB_225 = 1, + TX_SW1_LB_400 = 5, + TX_SW1_LB_575 = 2, + TX_SW1_LB_1000 = 6, + TX_SW1_LB_1700 = 0, + TX_SW1_LB_2750 = 4 + }; + + enum tx_sw2_t { + TX_SW2_LB_80 = 7, + TX_SW2_LB_160 = 3, + TX_SW2_LB_225 = 5, + TX_SW2_LB_400 = 1, + TX_SW2_LB_575 = 6, + TX_SW2_LB_1000 = 2, + TX_SW2_LB_1700 = 4, + TX_SW2_LB_2750 = 0 + }; + + enum trx_sw_t { + TRX1_SW_TX_HB = 2, + TRX1_SW_TX_LB = 1, + TRX1_SW_RX = 4, + TRX2_SW_TX_HB = 2, + TRX2_SW_TX_LB = 4, + TRX2_SW_RX = 1 + }; + + enum rx_sw1_t { + RX_SW1_LB_B2 = 4, + RX_SW1_LB_B3 = 5, + RX_SW1_LB_B4 = 2, + RX_SW1_LB_B5 = 3, + RX_SW1_LB_B6 = 0, + RX_SW1_LB_B7 = 1, + RX_SW1_OFF = 7 + + }; + + enum rx_sw2_t { + RX_SW2_LB_B2 = 5, + RX_SW2_LB_B3 = 4, + RX_SW2_LB_B4 = 3, + RX_SW2_LB_B5 = 2, + RX_SW2_LB_B6 = 1, + RX_SW2_LB_B7 = 0, + RX_SW2_OFF = 7 + }; + + enum rx_sw3_t { + RX_SW3_HBRX_LBTRX = 1, + RX_SW3_HBTRX_LBRX = 2, + RX_SW3_OFF = 0 // or 3 + }; + + enum tx_amp_t { TX_AMP_HF_ON = 2, TX_AMP_LF_ON = 1, TX_AMP_OFF = 3 }; + + /************************************************************************ + * API calls + ***********************************************************************/ + virtual bool check_radio_config(); + + const std::string get_default_timing_mode() + { + return TIMING_MODE_2R2T; + }; + + /*! Run a loopback self test. + * + * This will write data to the AD936x and read it back again. + * If this test fails, it generally means the interface is broken, + * so we assume it passes and throw otherwise. Running this requires + * a core that we can peek and poke the loopback values into. + * + * \param iface An interface to the associated radio control core + * \param iface The radio control core's address to write the loopback value + * \param iface The radio control core's readback address to read back the returned + * value + * + * \throws a uhd::runtime_error if the loopback value didn't match. + */ + void loopback_self_test(std::function<void(uint32_t)> poker_functor, + std::function<uint64_t()> peeker_functor); + + uint32_t get_rx_switches( + const size_t chan, const double freq, const std::string& ant); + + uint32_t get_tx_switches(const size_t chan, const double freq); + + uint32_t get_idle_switches(); + + uint32_t get_tx_led(); + uint32_t get_rx_led(); + uint32_t get_txrx_led(); + uint32_t get_idle_led(); +}; /* class radio_ctrl_impl */ + +}} /* namespace uhd::rfnoc */ + +#endif /* INCLUDED_LIBUHD_RFNOC_E320_RADIO_CTRL_IMPL_HPP */ +// vim: sw=4 et: diff --git a/host/lib/usrp/dboard/neon/neon_regs.hpp b/host/lib/usrp/dboard/e3xx/e320_regs.hpp index d1ff940c6..f5d28a63e 100644 --- a/host/lib/usrp/dboard/neon/neon_regs.hpp +++ b/host/lib/usrp/dboard/e3xx/e320_regs.hpp @@ -4,8 +4,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#ifndef INCLUDED_NEON_REGS_HPP -#define INCLUDED_NEON_REGS_HPP +#ifndef INCLUDED_E320_REGS_HPP +#define INCLUDED_E320_REGS_HPP #include <uhd/config.hpp> #include <cstdint> @@ -22,4 +22,4 @@ static const uint32_t TRX_LED_GRN_SHIFT = 0; static const uint32_t TX_LED_RED_SHIFT = 1; static const uint32_t RX_LED_GRN_SHIFT = 2; -#endif /* INCLUDED_NEON_REGS_HPP */ +#endif /* INCLUDED_E320_REGS_HPP */ diff --git a/host/lib/usrp/dboard/neon/neon_ad9361_iface.cpp b/host/lib/usrp/dboard/e3xx/e3xx_ad9361_iface.cpp index a9cf28fc2..d9cadc86f 100644 --- a/host/lib/usrp/dboard/neon/neon_ad9361_iface.cpp +++ b/host/lib/usrp/dboard/e3xx/e3xx_ad9361_iface.cpp @@ -4,17 +4,17 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include "neon_ad9361_iface.hpp" +#include "e3xx_ad9361_iface.hpp" #include <uhd/exception.hpp> #include <uhd/utils/log.hpp> #include <boost/format.hpp> using namespace uhd; -class neon_ad9361_iface : public ad9361_ctrl +class e3xx_ad9361_iface : public ad9361_ctrl { public: - neon_ad9361_iface(rpc_client::sptr rpcc) + e3xx_ad9361_iface(rpc_client::sptr rpcc) : _rpcc(rpcc), _rpc_prefix("db_0_"), _log_prefix("AD9361") { UHD_LOG_TRACE( @@ -46,7 +46,7 @@ public: double set_clock_rate(const double rate) { return _rpcc->request_with_token<double>( - this->_rpc_prefix + "set_clock_rate", rate); + E3XX_RATE_TIMEOUT, this->_rpc_prefix + "set_catalina_clock_rate", rate); } void set_active_chains(bool tx1, bool tx2, bool rx1, bool rx2) @@ -58,7 +58,7 @@ public: double tune(const std::string& which, const double value) { return _rpcc->request_with_token<double>( - this->_rpc_prefix + "tune", which, value); + E3XX_TUNE_TIMEOUT, this->_rpc_prefix + "catalina_tune", which, value); } void set_dc_offset_auto(const std::string& which, const bool on) @@ -139,17 +139,18 @@ private: const std::string _log_prefix; }; -//! Factory function for Neon's AD9361 RPC Controller +//! Factory function for E3xx's AD9361 RPC Controller ad9361_ctrl::sptr make_rpc(rpc_client::sptr rpcc) { - return ad9361_ctrl::sptr(new neon_ad9361_iface(rpcc)); + return ad9361_ctrl::sptr(new e3xx_ad9361_iface(rpcc)); } /*! Helper function to convert direction and channel to the 'which' required by most Catalina driver functions */ -std::string get_which_ad9361_chain(const direction_t dir, const size_t chan) +std::string get_which_ad9361_chain(const direction_t dir, const size_t chan, const bool fe_swap) { UHD_ASSERT_THROW(dir == RX_DIRECTION or dir == TX_DIRECTION); UHD_ASSERT_THROW(chan == 0 or chan == 1); - return str(boost::format("%s%d") % (dir == RX_DIRECTION ? "RX" : "TX") % (chan + 1)); + size_t ad9361_chan = fe_swap ? (chan ? 0 : 1) : chan; + return str(boost::format("%s%d") % (dir == RX_DIRECTION ? "RX" : "TX") % (ad9361_chan + 1)); } diff --git a/host/lib/usrp/dboard/e3xx/e3xx_ad9361_iface.hpp b/host/lib/usrp/dboard/e3xx/e3xx_ad9361_iface.hpp new file mode 100644 index 000000000..129015420 --- /dev/null +++ b/host/lib/usrp/dboard/e3xx/e3xx_ad9361_iface.hpp @@ -0,0 +1,28 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_LIBUHD_RFNOC_E3XX_AD9361_IFACE_HPP +#define INCLUDED_LIBUHD_RFNOC_E3XX_AD9361_IFACE_HPP + +# include <uhd/types/direction.hpp> +# include <uhd/types/filters.hpp> +# include <uhd/types/sensors.hpp> +# include <uhdlib/usrp/common/ad9361_ctrl.hpp> +# include <uhdlib/utils/rpc.hpp> +# include <memory> +# include <string> +# include <vector> + +using namespace uhd; +using namespace uhd::usrp; + +static constexpr size_t E3XX_TUNE_TIMEOUT = 60000; +static constexpr size_t E3XX_RATE_TIMEOUT = 60000; +ad9361_ctrl::sptr make_rpc(rpc_client::sptr rpcc); +std::string get_which_ad9361_chain(const direction_t dir, const size_t chan, const bool fe_swap=false); + +#endif /* INCLUDED_LIBUHD_RFNOC_E3XX_AD9361_IFACE_HPP */ +// vim: sw=4 et: diff --git a/host/lib/usrp/dboard/neon/neon_bands.cpp b/host/lib/usrp/dboard/e3xx/e3xx_bands.cpp index 303d2801d..001cf5d1b 100644 --- a/host/lib/usrp/dboard/neon/neon_bands.cpp +++ b/host/lib/usrp/dboard/e3xx/e3xx_bands.cpp @@ -4,12 +4,12 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include "neon_constants.hpp" -#include "neon_radio_ctrl_impl.hpp" +#include "e3xx_constants.hpp" +#include "e3xx_radio_ctrl_impl.hpp" #include <uhd/utils/math.hpp> /* - * Neon frequency bands: + * E320 frequency bands: * * For RX: * Band Freq BSEL-210 BSEL-543 TX/RX RX2 @@ -41,7 +41,41 @@ * LB_1000 723.8-1154.9 RF4 110 RF3 010 RF1 001 RF3 100 * LB_1700 1154.9-1842.6 RF1 000 RF2 100 RF1 001 RF3 100 * LB_2750 1842.6-2940.0 RF2 100 RF1 000 RF1 001 RF3 100 - * HB_5850 > 2490.0 --- --- --- --- RF2 010 RF2 010 + * HB_5850 > 2940.0 --- --- --- --- RF2 010 RF2 010 + * + */ + +/* + * E31x frequency bands: + * + * For RX: + * Band Freq RX_BSEL-210 RXC_BSEL-10 RXB_BSEL-10 RX2 TX/RX + * VCRX_V1_V2 VCTXRX_V1_V2 + * chan 1 | chan 2 + * --------------------------------------------------------------------------------- + * LB_B2: < 450 RF5 100 J2 10 -- 00 01 J2 10 J1 01 + * LB_B3: 450-700 RF3 010 J3 11 -- 00 01 J2 10 J1 01 + * LB_B4: 700-1200 RF1 000 J1 01 -- 00 01 J2 10 J1 01 + * LB_B5: 1200-1800 RF2 001 -- 00 J2 10 01 J2 10 J1 01 + * LB_B6: 1800-2350 RF4 011 -- 00 J3 11 01 J2 10 J1 01 + * LB_B7: 2350-2600 RF6 101 -- 00 J1 01 01 J2 10 J1 01 + * HB: 2600+ --- 111 -- 00 -- 00 10 J2 10 J1 01 + * + * + * For TX: + * Band-Freq TX_BSEL-210 TX/RX + VCTXRX_V1_V2 + * chan 1 | chan 2 + * ------------------------------------------------------------ + * LB_80 < 117.7 RF8 111 J1 01 J2 10 + * LB_160 117.7-178.2 RF7 110 J1 01 J2 10 + * LB_225 178.2-284.3 RF6 101 J1 01 J2 10 + * LB_400 284.3-453.7 RF5 100 J1 01 J2 10 + * LB_575 453.7-723.8 RF4 011 J1 01 J2 10 + * LB_1000 723.8-1154.9 RF3 010 J1 01 J2 10 + * LB_1700 1154.9-1842.6 RF2 001 J1 01 J2 10 + * LB_2750 1842.6-2940.0 RF1 000 J1 01 J2 10 + * HB_5850 > 2940.0 RF8 111 J3 11 J3 11 * */ @@ -58,19 +92,19 @@ namespace { * * The following constants define lower cutoff frequencies for each band. * LB_B2 does not have a lower cutoff frequency, it is implied by - * AD9361_MIN_FREQ. NEON_RX_BAND1_MIN_FREQ is the cutover frequency + * AD9361_MIN_FREQ. E3XX_RX_BAND1_MIN_FREQ is the cutover frequency * for switching from LB_B2 to LB_B3, and so on. * * Bands 1-6 have both high- and low-pass filters (effectively band * passes). Frequencies need to be chosen to allow as much of the full * bandwidth through unattenuated. */ -constexpr double NEON_RX_LB_BAND3_MIN_FREQ = 450e6; -constexpr double NEON_RX_LB_BAND4_MIN_FREQ = 700e6; -constexpr double NEON_RX_LB_BAND5_MIN_FREQ = 1200e6; -constexpr double NEON_RX_LB_BAND6_MIN_FREQ = 1800e6; -constexpr double NEON_RX_LB_BAND7_MIN_FREQ = 2350e6; -constexpr double NEON_RX_HB_MIN_FREQ = 2600e6; +constexpr double E3XX_RX_LB_BAND3_MIN_FREQ = 450e6; +constexpr double E3XX_RX_LB_BAND4_MIN_FREQ = 700e6; +constexpr double E3XX_RX_LB_BAND5_MIN_FREQ = 1200e6; +constexpr double E3XX_RX_LB_BAND6_MIN_FREQ = 1800e6; +constexpr double E3XX_RX_LB_BAND7_MIN_FREQ = 2350e6; +constexpr double E3XX_RX_HB_MIN_FREQ = 2600e6; /* Note on the TX filter bank: * @@ -78,43 +112,42 @@ constexpr double NEON_RX_HB_MIN_FREQ = 2600e6; * * The following constants define lower cutoff frequencies for each band. * LB_80 does not have a lower cutoff frequency, it is implied by - * AD9361_MIN_FREQ. NEON_TX_LB_160_MIN_FREQ is the cutover frequency + * AD9361_MIN_FREQ. E3XX_TX_LB_160_MIN_FREQ is the cutover frequency * for switching from LB_80 to LB_160, and so on. * - * On current Neon revisions, all filters on the TX filter bank are + * All filters on the TX filter bank are * low pass filters (no high pass filters). * Frequencies need to be chosen to allow as much of the full bandwidth * through unattenuated (so don't go all the way up to the cutoff frequency * of that filter). */ -constexpr double NEON_TX_LB_160_MIN_FREQ = 117.7e6; -constexpr double NEON_TX_LB_225_MIN_FREQ = 178.2e6; -constexpr double NEON_TX_LB_400_MIN_FREQ = 284.3e6; -constexpr double NEON_TX_LB_575_MIN_FREQ = 453.7e6; -constexpr double NEON_TX_LB_1000_MIN_FREQ = 723.8e6; -constexpr double NEON_TX_LB_1700_MIN_FREQ = 1154.9e6; -constexpr double NEON_TX_LB_2750_MIN_FREQ = 1842.6e6; -constexpr double NEON_TX_HB_MIN_FREQ = 2940.0e6; +constexpr double E3XX_TX_LB_160_MIN_FREQ = 117.7e6; +constexpr double E3XX_TX_LB_225_MIN_FREQ = 178.2e6; +constexpr double E3XX_TX_LB_400_MIN_FREQ = 284.3e6; +constexpr double E3XX_TX_LB_575_MIN_FREQ = 453.7e6; +constexpr double E3XX_TX_LB_1000_MIN_FREQ = 723.8e6; +constexpr double E3XX_TX_LB_1700_MIN_FREQ = 1154.9e6; +constexpr double E3XX_TX_LB_2750_MIN_FREQ = 1842.6e6; +constexpr double E3XX_TX_HB_MIN_FREQ = 2940.0e6; } // namespace -neon_radio_ctrl_impl::rx_band neon_radio_ctrl_impl::_map_freq_to_rx_band( - const double freq) +e3xx_radio_ctrl_impl::rx_band e3xx_radio_ctrl_impl::map_freq_to_rx_band(const double freq) { - neon_radio_ctrl_impl::rx_band band; + e3xx_radio_ctrl_impl::rx_band band; if (fp_compare_epsilon<double>(freq) < AD9361_RX_MIN_FREQ) { band = rx_band::INVALID_BAND; - } else if (fp_compare_epsilon<double>(freq) < NEON_RX_LB_BAND3_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_RX_LB_BAND3_MIN_FREQ) { band = rx_band::LB_B2; - } else if (fp_compare_epsilon<double>(freq) < NEON_RX_LB_BAND4_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_RX_LB_BAND4_MIN_FREQ) { band = rx_band::LB_B3; - } else if (fp_compare_epsilon<double>(freq) < NEON_RX_LB_BAND5_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_RX_LB_BAND5_MIN_FREQ) { band = rx_band::LB_B4; - } else if (fp_compare_epsilon<double>(freq) < NEON_RX_LB_BAND6_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_RX_LB_BAND6_MIN_FREQ) { band = rx_band::LB_B5; - } else if (fp_compare_epsilon<double>(freq) < NEON_RX_LB_BAND7_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_RX_LB_BAND7_MIN_FREQ) { band = rx_band::LB_B6; - } else if (fp_compare_epsilon<double>(freq) < NEON_RX_HB_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_RX_HB_MIN_FREQ) { band = rx_band::LB_B7; } else if (fp_compare_epsilon<double>(freq) <= AD9361_RX_MAX_FREQ) { band = rx_band::HB; @@ -125,28 +158,27 @@ neon_radio_ctrl_impl::rx_band neon_radio_ctrl_impl::_map_freq_to_rx_band( return band; } -neon_radio_ctrl_impl::tx_band neon_radio_ctrl_impl::_map_freq_to_tx_band( - const double freq) +e3xx_radio_ctrl_impl::tx_band e3xx_radio_ctrl_impl::map_freq_to_tx_band(const double freq) { - neon_radio_ctrl_impl::tx_band band; + e3xx_radio_ctrl_impl::tx_band band; if (fp_compare_epsilon<double>(freq) < AD9361_TX_MIN_FREQ) { band = tx_band::INVALID_BAND; - } else if (fp_compare_epsilon<double>(freq) < NEON_TX_LB_160_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_TX_LB_160_MIN_FREQ) { band = tx_band::LB_80; - } else if (fp_compare_epsilon<double>(freq) < NEON_TX_LB_225_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_TX_LB_225_MIN_FREQ) { band = tx_band::LB_160; - } else if (fp_compare_epsilon<double>(freq) < NEON_TX_LB_400_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_TX_LB_400_MIN_FREQ) { band = tx_band::LB_225; - } else if (fp_compare_epsilon<double>(freq) < NEON_TX_LB_575_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_TX_LB_575_MIN_FREQ) { band = tx_band::LB_400; - } else if (fp_compare_epsilon<double>(freq) < NEON_TX_LB_1000_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_TX_LB_1000_MIN_FREQ) { band = tx_band::LB_575; - } else if (fp_compare_epsilon<double>(freq) < NEON_TX_LB_1700_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_TX_LB_1700_MIN_FREQ) { band = tx_band::LB_1000; - } else if (fp_compare_epsilon<double>(freq) < NEON_TX_LB_2750_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_TX_LB_2750_MIN_FREQ) { band = tx_band::LB_1700; - } else if (fp_compare_epsilon<double>(freq) < NEON_TX_HB_MIN_FREQ) { + } else if (fp_compare_epsilon<double>(freq) < E3XX_TX_HB_MIN_FREQ) { band = tx_band::LB_2750; } else if (fp_compare_epsilon<double>(freq) <= AD9361_TX_MAX_FREQ) { band = tx_band::HB; diff --git a/host/lib/usrp/dboard/neon/neon_constants.hpp b/host/lib/usrp/dboard/e3xx/e3xx_constants.hpp index 42cfb6579..53f64d837 100644 --- a/host/lib/usrp/dboard/neon/neon_constants.hpp +++ b/host/lib/usrp/dboard/e3xx/e3xx_constants.hpp @@ -4,8 +4,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#ifndef INCLUDED_LIBUHD_NEON_CONSTANTS_HPP -#define INCLUDED_LIBUHD_NEON_CONSTANTS_HPP +#ifndef INCLUDED_LIBUHD_E3XX_CONSTANTS_HPP +#define INCLUDED_LIBUHD_E3XX_CONSTANTS_HPP #include <cstddef> #include <string> @@ -25,7 +25,7 @@ static constexpr double AD9361_TX_MAX_FREQ = 6.0e9; // Hz static constexpr double AD9361_RX_MIN_FREQ = 70.0e6; // Hz static constexpr double AD9361_RX_MAX_FREQ = 6.0e9; // Hz -static constexpr double NEON_RADIO_RATE = 16e6; // Hz +static constexpr double E3XX_RADIO_RATE = 16e6; // Hz static constexpr double AD9361_MIN_RX_GAIN = 0.0; // dB static constexpr double AD9361_MAX_RX_GAIN = 76; // dB @@ -34,19 +34,23 @@ static constexpr double AD9361_MIN_TX_GAIN = 0.0; // dB static constexpr double AD9361_MAX_TX_GAIN = 89.75; // dB static constexpr double AD9361_TX_GAIN_STEP = 0.25; // dB +static constexpr bool E3XX_DEFAULT_AUTO_DC_OFFSET = true; +static constexpr bool E3XX_DEFAULT_AUTO_IQ_BALANCE = true; +static constexpr bool E3XX_DEFAULT_AGC_ENABLE = false; -static constexpr bool NEON_DEFAULT_AUTO_DC_OFFSET = true; -static constexpr bool NEON_DEFAULT_AUTO_IQ_BALANCE = true; -static constexpr bool NEON_DEFAULT_AGC_ENABLE = false; +static constexpr double E3XX_DEFAULT_GAIN = 0.0; +static constexpr double E3XX_DEFAULT_FREQ = 2.4e9; // Hz +static constexpr double E3XX_DEFAULT_BANDWIDTH = 40e6; // Hz +static constexpr char E3XX_DEFAULT_RX_ANTENNA[] = "RX2"; +static constexpr char E3XX_DEFAULT_TX_ANTENNA[] = "TX/RX"; -static constexpr double NEON_DEFAULT_GAIN = 0.0; -static constexpr double NEON_DEFAULT_FREQ = 2.4e9; // Hz -static constexpr double NEON_DEFAULT_BANDWIDTH = 40e6; // Hz -static constexpr char NEON_DEFAULT_RX_ANTENNA[] = "RX2"; -static constexpr char NEON_DEFAULT_TX_ANTENNA[] = "TX/RX"; +static const std::vector<std::string> E3XX_RX_ANTENNAS = {"RX2", "TX/RX"}; -static const std::vector<std::string> NEON_RX_ANTENNAS = {"RX2", "TX/RX"}; +static constexpr size_t E3XX_NUM_CHANS = 2; -static constexpr size_t NEON_NUM_CHANS = 2; - -#endif /* INCLUDED_LIBUHD_NEON_CONSTANTS_HPP */ +static constexpr char TIMING_MODE_2R2T[] = "2R2T"; +static constexpr char TIMING_MODE_1R1T[] = "1R1T"; +static constexpr char MIMO[] = "MIMO"; // 2R2T +static constexpr char SISO_TX1[] = "SISO_TX1"; // 1R1T +static constexpr char SISO_TX0[] = "SISO_TX0"; // 1R1T +#endif /* INCLUDED_LIBUHD_E3XX_CONSTANTS_HPP */ diff --git a/host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_impl.cpp new file mode 100644 index 000000000..989b73b82 --- /dev/null +++ b/host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_impl.cpp @@ -0,0 +1,343 @@ +// +// Copyright 2018 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include "e3xx_radio_ctrl_impl.hpp" +#include "e3xx_constants.hpp" +#include <uhd/rfnoc/node_ctrl_base.hpp> +#include <uhd/transport/chdr.hpp> +#include <uhd/types/direction.hpp> +#include <uhd/types/eeprom.hpp> +#include <uhd/utils/algorithm.hpp> +#include <uhd/utils/log.hpp> +#include <uhd/utils/math.hpp> +#include <boost/algorithm/string.hpp> +#include <boost/format.hpp> +#include <boost/make_shared.hpp> +#include <cmath> +#include <cstdlib> +#include <sstream> + +using namespace uhd; +using namespace uhd::usrp; +using namespace uhd::rfnoc; +using namespace uhd::math::fp_compare; + +/****************************************************************************** + * Structors + *****************************************************************************/ +e3xx_radio_ctrl_impl::e3xx_radio_ctrl_impl() +{ + UHD_LOG_TRACE(unique_id(), "Entering e3xx_radio_ctrl_impl ctor..."); + const char radio_slot_name[1] = {'A'}; + _radio_slot = radio_slot_name[get_block_id().get_block_count()]; + UHD_LOG_TRACE(unique_id(), "Radio slot: " << _radio_slot); + _rpc_prefix = "db_0_"; + + _init_defaults(); + _init_peripherals(); + _init_prop_tree(); +} + +e3xx_radio_ctrl_impl::~e3xx_radio_ctrl_impl() +{ + UHD_LOG_TRACE(unique_id(), "e3xx_radio_ctrl_impl::dtor() "); +} + + +/****************************************************************************** + * API Calls + *****************************************************************************/ + +void e3xx_radio_ctrl_impl::set_streaming_mode( + const bool tx1, const bool tx2, const bool rx1, const bool rx2) +{ + UHD_LOG_TRACE(unique_id(), "Setting up streaming ...") + const size_t num_rx = rx1 + rx2; + const size_t num_tx = tx1 + tx2; + + // setup the active chains in the codec + if ((num_rx + num_tx) == 0) { + // Ensure at least one RX chain is enabled so AD9361 outputs a sample clock + _ad9361->set_active_chains(true, false, true, false); + } else { + // setup the active chains in the codec + _ad9361->set_active_chains(tx1, tx2, rx1, rx2); + } + + // setup 1R1T/2R2T mode in catalina and fpga + // The Catalina interface in the fpga needs to know which TX channel to use for + // the data on the LVDS lines. + if ((num_rx == 2) or (num_tx == 2)) { + // AD9361 is in 1R1T mode + _ad9361->set_timing_mode(this->get_default_timing_mode()); + this->set_channel_mode(MIMO); + } else { + // AD9361 is in 1R1T mode + _ad9361->set_timing_mode(TIMING_MODE_1R1T); + + // Set to SIS0_TX1 if we're using the second TX antenna, otherwise + // default to SISO_TX0 + this->set_channel_mode(tx2 ? SISO_TX1 : SISO_TX0); + } +} + +void e3xx_radio_ctrl_impl::set_channel_mode(const std::string& channel_mode) +{ + // MIMO for 2R2T mode for 2 channels + // SISO_TX1 for 1R1T mode for 1 channel - TX1 + // SISO_TX0 for 1R1T mode for 1 channel - TX0 + + _rpcc->request_with_token<void>("set_channel_mode", channel_mode); +} + +double e3xx_radio_ctrl_impl::set_rate(const double rate) +{ + std::lock_guard<std::mutex> l(_set_lock); + UHD_LOG_DEBUG(unique_id(), "Asking for clock rate " << rate / 1e6 << " MHz\n"); + double actual_tick_rate = _ad9361->set_clock_rate(rate); + UHD_LOG_DEBUG( + unique_id(), "Actual clock rate " << actual_tick_rate / 1e6 << " MHz\n"); + + radio_ctrl_impl::set_rate(rate); + return rate; +} + +void e3xx_radio_ctrl_impl::set_tx_antenna(const std::string& ant, const size_t chan) +{ + if (ant != get_tx_antenna(chan)) { + throw uhd::value_error( + str(boost::format("[%s] Requesting invalid TX antenna value: %s") + % unique_id() % ant)); + } + radio_ctrl_impl::set_tx_antenna(ant, chan); + // We can't actually set the TX antenna, so let's stop here. +} + +void e3xx_radio_ctrl_impl::set_rx_antenna(const std::string& ant, const size_t chan) +{ + UHD_ASSERT_THROW(chan <= E3XX_NUM_CHANS); + if (std::find(E3XX_RX_ANTENNAS.begin(), E3XX_RX_ANTENNAS.end(), ant) + == E3XX_RX_ANTENNAS.end()) { + throw uhd::value_error( + str(boost::format("[%s] Requesting invalid RX antenna value: %s") + % unique_id() % ant)); + } + UHD_LOG_TRACE(unique_id(), "Setting RX antenna to " << ant << " for chan " << chan); + + radio_ctrl_impl::set_rx_antenna(ant, chan); + _set_atr_bits(chan); +} + +double e3xx_radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan) +{ + UHD_LOG_TRACE(unique_id(), "set_tx_frequency(f=" << freq << ", chan=" << chan << ")"); + std::lock_guard<std::mutex> l(_set_lock); + + double clipped_freq = uhd::clip(freq, AD9361_TX_MIN_FREQ, AD9361_TX_MAX_FREQ); + + double coerced_freq = + _ad9361->tune(get_which_ad9361_chain(TX_DIRECTION, chan, _fe_swap), clipped_freq); + radio_ctrl_impl::set_tx_frequency(coerced_freq, chan); + // Front-end switching + _set_atr_bits(chan); + + return coerced_freq; +} + +double e3xx_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan) +{ + UHD_LOG_TRACE(unique_id(), "set_rx_frequency(f=" << freq << ", chan=" << chan << ")"); + std::lock_guard<std::mutex> l(_set_lock); + + double clipped_freq = uhd::clip(freq, AD9361_RX_MIN_FREQ, AD9361_RX_MAX_FREQ); + + double coerced_freq = + _ad9361->tune(get_which_ad9361_chain(RX_DIRECTION, chan, _fe_swap), clipped_freq); + radio_ctrl_impl::set_rx_frequency(coerced_freq, chan); + // Front-end switching + _set_atr_bits(chan); + + return coerced_freq; +} + +double e3xx_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan) +{ + std::lock_guard<std::mutex> l(_set_lock); + double clipped_bw = + _ad9361->set_bw_filter(get_which_ad9361_chain(RX_DIRECTION, chan, _fe_swap), bandwidth); + return radio_ctrl_impl::set_rx_bandwidth(clipped_bw, chan); +} + +double e3xx_radio_ctrl_impl::set_tx_bandwidth(const double bandwidth, const size_t chan) +{ + std::lock_guard<std::mutex> l(_set_lock); + double clipped_bw = + _ad9361->set_bw_filter(get_which_ad9361_chain(TX_DIRECTION, chan, _fe_swap), bandwidth); + return radio_ctrl_impl::set_tx_bandwidth(clipped_bw, chan); +} + +double e3xx_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan) +{ + std::lock_guard<std::mutex> l(_set_lock); + UHD_LOG_TRACE(unique_id(), "set_tx_gain(gain=" << gain << ", chan=" << chan << ")"); + double clip_gain = uhd::clip(gain, AD9361_MIN_TX_GAIN, AD9361_MAX_TX_GAIN); + _ad9361->set_gain(get_which_ad9361_chain(TX_DIRECTION, chan, _fe_swap), clip_gain); + radio_ctrl_impl::set_tx_gain(clip_gain, chan); + return clip_gain; +} + +double e3xx_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan) +{ + std::lock_guard<std::mutex> l(_set_lock); + UHD_LOG_TRACE(unique_id(), "set_rx_gain(gain=" << gain << ", chan=" << chan << ")"); + double clip_gain = uhd::clip(gain, AD9361_MIN_RX_GAIN, AD9361_MAX_RX_GAIN); + _ad9361->set_gain(get_which_ad9361_chain(RX_DIRECTION, chan, _fe_swap), clip_gain); + radio_ctrl_impl::set_rx_gain(clip_gain, chan); + return clip_gain; +} + +size_t e3xx_radio_ctrl_impl::get_chan_from_dboard_fe( + const std::string& fe, const direction_t /* dir */ +) +{ + const size_t chan = boost::lexical_cast<size_t>(fe); + if (chan > _get_num_radios() - 1) { + UHD_LOG_WARNING(unique_id(), + boost::format("Invalid channel determined from dboard frontend %s.") % fe); + } + return chan; +} + +std::string e3xx_radio_ctrl_impl::get_dboard_fe_from_chan( + const size_t chan, const direction_t /* dir */ +) +{ + return std::to_string(chan); +} + +void e3xx_radio_ctrl_impl::set_rpc_client( + uhd::rpc_client::sptr rpcc, const uhd::device_addr_t& block_args) +{ + _rpcc = rpcc; + _block_args = block_args; + UHD_LOG_TRACE(unique_id(), "Instantiating AD9361 control object..."); + _ad9361 = make_rpc(_rpcc); + + UHD_LOG_TRACE(unique_id(), "Setting Catalina Defaults... "); + // Initialize catalina + this->_init_codec(); + + if (block_args.has_key("identify")) { + const std::string identify_val = block_args.get("identify"); + int identify_duration = std::atoi(identify_val.c_str()); + if (identify_duration == 0) { + identify_duration = 5; + } + UHD_LOG_INFO(unique_id(), + "Running LED identification process for " << identify_duration + << " seconds."); + _identify_with_leds(identify_duration); + } + // Note: MCR gets set during the init() call (prior to this), which takes + // in arguments from the device args. So if block_args contains a + // master_clock_rate key, then it should better be whatever the device is + // configured to do. + _master_clock_rate = + _rpcc->request_with_token<double>(_rpc_prefix + "get_master_clock_rate"); + if (block_args.cast<double>("master_clock_rate", _master_clock_rate) + != _master_clock_rate) { + throw uhd::runtime_error(str( + boost::format("Master clock rate mismatch. Device returns %f MHz, " + "but should have been %f MHz.") + % (_master_clock_rate / 1e6) + % (block_args.cast<double>("master_clock_rate", _master_clock_rate) / 1e6))); + } + UHD_LOG_DEBUG( + unique_id(), "Master Clock Rate is: " << (_master_clock_rate / 1e6) << " MHz."); + this->set_rate(_master_clock_rate); + + // Loopback test + for (size_t chan = 0; chan < _get_num_radios(); chan++) { + loopback_self_test( + [this, chan]( + const uint32_t value) { this->sr_write(regs::CODEC_IDLE, value, chan); }, + [this, chan]() { + return this->user_reg_read64(regs::RB_CODEC_READBACK, chan); + }); + } + + const size_t db_idx = get_block_id().get_block_count(); + _tree->access<eeprom_map_t>(_root_path / "eeprom") + .add_coerced_subscriber([this, db_idx](const eeprom_map_t& db_eeprom) { + this->_rpcc->notify_with_token("set_db_eeprom", db_idx, db_eeprom); + }) + .set_publisher([this, db_idx]() { + return this->_rpcc->request_with_token<eeprom_map_t>("get_db_eeprom", db_idx); + }); + + // Init sensors + for (const auto& dir : std::vector<direction_t>{RX_DIRECTION, TX_DIRECTION}) { + for (size_t chan_idx = 0; chan_idx < E3XX_NUM_CHANS; chan_idx++) { + _init_mpm_sensors(dir, chan_idx); + } + } +} + +bool e3xx_radio_ctrl_impl::get_lo_lock_status(const direction_t dir) +{ + if (not(bool(_rpcc))) { + UHD_LOG_DEBUG(unique_id(), "Reported no LO lock due to lack of RPC connection."); + return false; + } + + const std::string trx = (dir == RX_DIRECTION) ? "rx" : "tx"; + bool lo_lock = + _rpcc->request_with_token<bool>(_rpc_prefix + "get_ad9361_lo_lock", trx); + UHD_LOG_TRACE(unique_id(), + "AD9361 " << trx << " LO reports lock: " << (lo_lock ? "Yes" : "No")); + + return lo_lock; +} + +void e3xx_radio_ctrl_impl::_set_atr_bits(const size_t chan) +{ + const auto rx_freq = radio_ctrl_impl::get_rx_frequency(chan); + const auto tx_freq = radio_ctrl_impl::get_tx_frequency(chan); + const auto rx_ant = radio_ctrl_impl::get_rx_antenna(chan); + const uint32_t rx_regs = this->get_rx_switches(chan, rx_freq, rx_ant); + const uint32_t tx_regs = this->get_tx_switches(chan, tx_freq); + const uint32_t idle_regs = this->get_idle_switches(); + + _db_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_IDLE, idle_regs); + _db_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_RX_ONLY, rx_regs); + _db_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_TX_ONLY, tx_regs); + _db_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_FULL_DUPLEX, rx_regs | tx_regs); + + // The LED signal names are reversed, but are consistent with the schematic + const bool is_txrx = rx_ant == "TX/RX"; + const int idle_led = 0; + const int rx_led = this->get_rx_led(); + const int tx_led = this->get_tx_led(); + const int txrx_led = this->get_txrx_led(); + + _leds_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_IDLE, idle_led); + _leds_gpio[chan]->set_atr_reg( + usrp::gpio_atr::ATR_REG_RX_ONLY, is_txrx ? txrx_led : rx_led); + _leds_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_TX_ONLY, tx_led); + _leds_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_FULL_DUPLEX, rx_led | tx_led); +} + +void e3xx_radio_ctrl_impl::_identify_with_leds(const int identify_duration) +{ + auto end_time = + std::chrono::steady_clock::now() + std::chrono::seconds(identify_duration); + bool led_state = true; + while (std::chrono::steady_clock::now() < end_time) { + // Add update_leds + led_state = !led_state; + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + } +} diff --git a/host/lib/usrp/dboard/neon/neon_radio_ctrl_impl.hpp b/host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_impl.hpp index 88d1eed73..41c2c4594 100644 --- a/host/lib/usrp/dboard/neon/neon_radio_ctrl_impl.hpp +++ b/host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_impl.hpp @@ -4,26 +4,26 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#ifndef INCLUDED_LIBUHD_RFNOC_NEON_RADIO_CTRL_IMPL_HPP -#define INCLUDED_LIBUHD_RFNOC_NEON_RADIO_CTRL_IMPL_HPP - -#include "neon_ad9361_iface.hpp" -#include <uhd/types/serial.hpp> -#include <uhd/usrp/dboard_manager.hpp> -#include <uhd/usrp/gpio_defs.hpp> -#include <uhdlib/rfnoc/radio_ctrl_impl.hpp> -#include <uhdlib/rfnoc/rpc_block_ctrl.hpp> -#include <uhdlib/usrp/cores/gpio_atr_3000.hpp> -#include <mutex> +#ifndef INCLUDED_LIBUHD_RFNOC_E3XX_RADIO_CTRL_IMPL_HPP +# define INCLUDED_LIBUHD_RFNOC_E3XX_RADIO_CTRL_IMPL_HPP + +# include "e3xx_ad9361_iface.hpp" +# include <uhd/types/serial.hpp> +# include <uhd/usrp/dboard_manager.hpp> +# include <uhd/usrp/gpio_defs.hpp> +# include <uhdlib/rfnoc/radio_ctrl_impl.hpp> +# include <uhdlib/rfnoc/rpc_block_ctrl.hpp> +# include <uhdlib/usrp/cores/gpio_atr_3000.hpp> +# include <mutex> namespace uhd { namespace rfnoc { -/*! \brief Provide access to an Magnesium radio. +/*! \brief Provide access to an E3xx radio. */ -class neon_radio_ctrl_impl : public radio_ctrl_impl, public rpc_block_ctrl +class e3xx_radio_ctrl_impl : public radio_ctrl_impl, public rpc_block_ctrl { public: - typedef boost::shared_ptr<neon_radio_ctrl_impl> sptr; + typedef boost::shared_ptr<e3xx_radio_ctrl_impl> sptr; //! Frequency bands for RX. Bands are a function of the analog filter banks enum class rx_band { INVALID_BAND, LB_B2, LB_B3, LB_B4, LB_B5, LB_B6, LB_B7, HB }; @@ -51,86 +51,53 @@ public: //! Channel select: enum chan_sel_t { CHAN1, CHAN2, BOTH }; - enum tx_sw1_t { - TX_SW1_LB_80 = 3, - TX_SW1_LB_160 = 7, - TX_SW1_LB_225 = 1, - TX_SW1_LB_400 = 5, - TX_SW1_LB_575 = 2, - TX_SW1_LB_1000 = 6, - TX_SW1_LB_1700 = 0, - TX_SW1_LB_2750 = 4 - }; - - enum tx_sw2_t { - TX_SW2_LB_80 = 7, - TX_SW2_LB_160 = 3, - TX_SW2_LB_225 = 5, - TX_SW2_LB_400 = 1, - TX_SW2_LB_575 = 6, - TX_SW2_LB_1000 = 2, - TX_SW2_LB_1700 = 4, - TX_SW2_LB_2750 = 0 - }; - - enum trx_sw_t { - TRX1_SW_TX_HB = 2, - TRX1_SW_TX_LB = 1, - TRX1_SW_RX = 4, - TRX2_SW_TX_HB = 2, - TRX2_SW_TX_LB = 4, - TRX2_SW_RX = 1 - }; - - enum rx_sw1_t { - RX_SW1_LB_B2 = 4, - RX_SW1_LB_B3 = 5, - RX_SW1_LB_B4 = 2, - RX_SW1_LB_B5 = 3, - RX_SW1_LB_B6 = 0, - RX_SW1_LB_B7 = 1, - RX_SW1_OFF = 7 - - }; - - enum rx_sw2_t { - RX_SW2_LB_B2 = 5, - RX_SW2_LB_B3 = 4, - RX_SW2_LB_B4 = 3, - RX_SW2_LB_B5 = 2, - RX_SW2_LB_B6 = 1, - RX_SW2_LB_B7 = 0, - RX_SW2_OFF = 7 - }; - - enum rx_sw3_t { - RX_SW3_HBRX_LBTRX = 1, - RX_SW3_HBTRX_LBRX = 2, - RX_SW3_OFF = 0 // or 3 - }; - - enum tx_amp_t { TX_AMP_HF_ON = 2, TX_AMP_LF_ON = 1, TX_AMP_OFF = 3 }; - /************************************************************************ * Structors ***********************************************************************/ - UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(neon_radio_ctrl) - virtual ~neon_radio_ctrl_impl(); + e3xx_radio_ctrl_impl(); + virtual ~e3xx_radio_ctrl_impl(); /************************************************************************ * API calls ***********************************************************************/ + // Note: We use the cached values in radio_ctrl_impl, so most getters are // not reimplemented here - - virtual bool check_radio_config(); + //! Set streaming mode - active chains, channel_mode, timing_mode + void set_streaming_mode( + const bool tx1, const bool tx2, const bool rx1, const bool rx2); //! Set which channel mode is used void set_channel_mode(const std::string& channel_mode); - //! Set streaming mode - active chains, channel_mode, timing_mode - void set_streaming_mode( - const bool tx1, const bool tx2, const bool rx1, const bool rx2); + double set_rate(const 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); + + double set_tx_frequency(const double freq, const size_t chan); + double set_rx_frequency(const double freq, const size_t chan); + double set_tx_bandwidth(const double bandwidth, const size_t chan); + double set_rx_bandwidth(const double bandwidth, const size_t chan); + + // gain + double set_tx_gain(const double gain, const size_t chan); + double set_rx_gain(const double gain, 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); + + void set_rpc_client(uhd::rpc_client::sptr rpcc, const uhd::device_addr_t& block_args); + +protected: + //! Map a frequency in Hz to an rx_band value. Will return + // rx_band::INVALID_BAND if the frequency is out of range. + rx_band map_freq_to_rx_band(const double freq); + //! Map a frequency in Hz to an tx_band value. Will return + // tx_band::INVALID_BAND if the frequency is out of range. + tx_band map_freq_to_tx_band(const double freq); + + virtual const std::string get_default_timing_mode() = 0; /*! Run a loopback self test. * @@ -146,27 +113,27 @@ public: * * \throws a uhd::runtime_error if the loopback value didn't match. */ - void loopback_self_test(std::function<void(uint32_t)> poker_functor, - std::function<uint64_t()> peeker_functor); + virtual void loopback_self_test(std::function<void(uint32_t)> poker_functor, + std::function<uint64_t()> peeker_functor) = 0; - double set_rate(const double rate); + virtual uint32_t get_rx_switches( + const size_t chan, const double freq, const std::string& ant) = 0; - void set_tx_antenna(const std::string& ant, const size_t chan); - void set_rx_antenna(const std::string& ant, const size_t chan); + virtual uint32_t get_tx_switches(const size_t chan, const double freq) = 0; - double set_tx_frequency(const double freq, const size_t chan); - double set_rx_frequency(const double freq, const size_t chan); - double set_tx_bandwidth(const double bandwidth, const size_t chan); - double set_rx_bandwidth(const double bandwidth, const size_t chan); + virtual uint32_t get_idle_switches() = 0; - // gain - double set_tx_gain(const double gain, const size_t chan); - double set_rx_gain(const double gain, const size_t chan); + virtual uint32_t get_tx_led() = 0; + virtual uint32_t get_rx_led() = 0; + virtual uint32_t get_txrx_led() = 0; + virtual uint32_t get_idle_led() = 0; - 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); + //! Reference to the AD9361 controls + // e3xx_ad9361_iface::uptr _ad9361; + ad9361_ctrl::sptr _ad9361; - void set_rpc_client(uhd::rpc_client::sptr rpcc, const uhd::device_addr_t& block_args); + //! Swap RFA and RFB for catalina + bool _fe_swap; private: /************************************************************************** @@ -189,13 +156,6 @@ private: void _init_mpm_sensors(const direction_t dir, const size_t chan_idx); - //! Map a frequency in Hz to an rx_band value. Will return - // rx_band::INVALID_BAND if the frequency is out of range. - rx_band _map_freq_to_rx_band(const double freq); - //! Map a frequency in Hz to an tx_band value. Will return - // tx_band::INVALID_BAND if the frequency is out of range. - tx_band _map_freq_to_tx_band(const double freq); - /************************************************************************* * Sensors *************************************************************************/ @@ -210,11 +170,6 @@ private: // and resume normal operation. void _identify_with_leds(const int identify_duration); - uint32_t _get_rx_switches( - const size_t chan, const double freq, const std::string& ant); - - uint32_t _get_tx_switches(const size_t chan, const double freq); - void _set_atr_bits(const size_t chan); /************************************************************************** @@ -238,10 +193,6 @@ private: //! Reference to the SPI core uhd::spi_iface::sptr _spi; - //! Reference to the AD9361 controls - // neon_ad9361_iface::uptr _ad9361; - ad9361_ctrl::sptr _ad9361; - //! ATR controls. These control the AD9361 gain // up/down bits. // Every radio channel gets its own ATR state register. @@ -260,4 +211,5 @@ private: }} /* namespace uhd::rfnoc */ -#endif /* INCLUDED_LIBUHD_RFNOC_NEON_RADIO_CTRL_IMPL_HPP */ +#endif /* INCLUDED_LIBUHD_RFNOC_E3XX_RADIO_CTRL_IMPL_HPP */ +// vim: sw=4 et: diff --git a/host/lib/usrp/dboard/neon/neon_radio_ctrl_init.cpp b/host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_init.cpp index 783f0c7b2..5b33b33e7 100644 --- a/host/lib/usrp/dboard/neon/neon_radio_ctrl_init.cpp +++ b/host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_init.cpp @@ -4,8 +4,8 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include "neon_constants.hpp" -#include "neon_radio_ctrl_impl.hpp" +#include "e3xx_constants.hpp" +#include "e3xx_radio_ctrl_impl.hpp" #include <uhd/transport/chdr.hpp> #include <uhd/types/eeprom.hpp> #include <uhd/types/sensors.hpp> @@ -56,7 +56,7 @@ uint32_t _extract_port_number( return radio_num * port_size + port_num; } -void neon_radio_ctrl_impl::_init_defaults() +void e3xx_radio_ctrl_impl::_init_defaults() { UHD_LOG_TRACE(unique_id(), "Initializing defaults..."); const size_t num_rx_chans = get_output_ports().size(); @@ -66,17 +66,17 @@ void neon_radio_ctrl_impl::_init_defaults() "Num TX chans: " << num_tx_chans << " Num RX chans: " << num_rx_chans); for (size_t chan = 0; chan < num_rx_chans; chan++) { - radio_ctrl_impl::set_rx_frequency(NEON_DEFAULT_FREQ, chan); - radio_ctrl_impl::set_rx_gain(NEON_DEFAULT_GAIN, chan); - radio_ctrl_impl::set_rx_antenna(NEON_DEFAULT_RX_ANTENNA, chan); - radio_ctrl_impl::set_rx_bandwidth(NEON_DEFAULT_BANDWIDTH, chan); + radio_ctrl_impl::set_rx_frequency(E3XX_DEFAULT_FREQ, chan); + radio_ctrl_impl::set_rx_gain(E3XX_DEFAULT_GAIN, chan); + radio_ctrl_impl::set_rx_antenna(E3XX_DEFAULT_RX_ANTENNA, chan); + radio_ctrl_impl::set_rx_bandwidth(E3XX_DEFAULT_BANDWIDTH, chan); } for (size_t chan = 0; chan < num_tx_chans; chan++) { - radio_ctrl_impl::set_tx_frequency(NEON_DEFAULT_FREQ, chan); - radio_ctrl_impl::set_tx_gain(NEON_DEFAULT_GAIN, chan); - radio_ctrl_impl::set_tx_antenna(NEON_DEFAULT_TX_ANTENNA, chan); - radio_ctrl_impl::set_tx_bandwidth(NEON_DEFAULT_BANDWIDTH, chan); + radio_ctrl_impl::set_tx_frequency(E3XX_DEFAULT_FREQ, chan); + radio_ctrl_impl::set_tx_gain(E3XX_DEFAULT_GAIN, chan); + radio_ctrl_impl::set_tx_antenna(E3XX_DEFAULT_TX_ANTENNA, chan); + radio_ctrl_impl::set_tx_bandwidth(E3XX_DEFAULT_BANDWIDTH, chan); } /** Update default SPP (overwrites the default value from the XML file) **/ @@ -89,7 +89,7 @@ void neon_radio_ctrl_impl::_init_defaults() _tree->access<int>(get_arg_path("spp") / "value").set(default_spp); } -void neon_radio_ctrl_impl::_init_peripherals() +void e3xx_radio_ctrl_impl::_init_peripherals() { UHD_LOG_TRACE(unique_id(), "Initializing peripherals..."); @@ -115,7 +115,7 @@ void neon_radio_ctrl_impl::_init_peripherals() _get_ctrl(0), regs::sr_addr(regs::FP_GPIO), regs::rb_addr(regs::RB_FP_GPIO)); } -void neon_radio_ctrl_impl::_init_frontend_subtree( +void e3xx_radio_ctrl_impl::_init_frontend_subtree( uhd::property_tree::sptr subtree, const size_t chan_idx) { const fs_path tx_fe_path = fs_path("tx_frontends") / chan_idx; @@ -124,10 +124,10 @@ void neon_radio_ctrl_impl::_init_frontend_subtree( "Adding non-RFNoC block properties for channel " << chan_idx << " to prop tree path " << tx_fe_path << " and " << rx_fe_path); // TX Standard attributes - subtree->create<std::string>(tx_fe_path / "name").set(str(boost::format("Neon"))); + subtree->create<std::string>(tx_fe_path / "name").set(str(boost::format("E3xx"))); subtree->create<std::string>(tx_fe_path / "connection").set("IQ"); // RX Standard attributes - subtree->create<std::string>(rx_fe_path / "name").set(str(boost::format("Neon"))); + subtree->create<std::string>(rx_fe_path / "name").set(str(boost::format("E3xx"))); subtree->create<std::string>(rx_fe_path / "connection").set("IQ"); // TX Antenna subtree->create<std::string>(tx_fe_path / "antenna" / "value") @@ -136,7 +136,7 @@ void neon_radio_ctrl_impl::_init_frontend_subtree( }) .set_publisher([this, chan_idx]() { return this->get_tx_antenna(chan_idx); }); subtree->create<std::vector<std::string>>(tx_fe_path / "antenna" / "options") - .set({NEON_DEFAULT_TX_ANTENNA}) + .set({E3XX_DEFAULT_TX_ANTENNA}) .add_coerced_subscriber([](const std::vector<std::string>&) { throw uhd::runtime_error("Attempting to update antenna options!"); }); @@ -147,7 +147,7 @@ void neon_radio_ctrl_impl::_init_frontend_subtree( }) .set_publisher([this, chan_idx]() { return this->get_rx_antenna(chan_idx); }); subtree->create<std::vector<std::string>>(rx_fe_path / "antenna" / "options") - .set(NEON_RX_ANTENNAS) + .set(E3XX_RX_ANTENNAS) .add_coerced_subscriber([](const std::vector<std::string>&) { throw uhd::runtime_error("Attempting to update antenna options!"); }); @@ -260,10 +260,10 @@ void neon_radio_ctrl_impl::_init_frontend_subtree( }); } -void neon_radio_ctrl_impl::_init_prop_tree() +void e3xx_radio_ctrl_impl::_init_prop_tree() { const fs_path fe_base = fs_path("dboards") / _radio_slot; - for (size_t chan_idx = 0; chan_idx < NEON_NUM_CHANS; chan_idx++) { + for (size_t chan_idx = 0; chan_idx < E3XX_NUM_CHANS; chan_idx++) { this->_init_frontend_subtree(_tree->subtree(fe_base), chan_idx); } @@ -383,25 +383,25 @@ void neon_radio_ctrl_impl::_init_prop_tree() } } -void neon_radio_ctrl_impl::_init_codec() +void e3xx_radio_ctrl_impl::_init_codec() { for (size_t chan = 0; chan < _get_num_radios(); chan++) { std::string rx_fe = get_which_ad9361_chain(RX_DIRECTION, chan); - this->set_rx_gain(NEON_DEFAULT_GAIN, chan); - this->set_rx_frequency(NEON_DEFAULT_FREQ, chan); - this->set_rx_antenna(NEON_DEFAULT_RX_ANTENNA, chan); - this->set_rx_bandwidth(NEON_DEFAULT_BANDWIDTH, chan); - _ad9361->set_dc_offset_auto(rx_fe, NEON_DEFAULT_AUTO_DC_OFFSET); - _ad9361->set_iq_balance_auto(rx_fe, NEON_DEFAULT_AUTO_IQ_BALANCE); - _ad9361->set_agc(rx_fe, NEON_DEFAULT_AGC_ENABLE); + this->set_rx_gain(E3XX_DEFAULT_GAIN, chan); + this->set_rx_frequency(E3XX_DEFAULT_FREQ, chan); + this->set_rx_antenna(E3XX_DEFAULT_RX_ANTENNA, chan); + this->set_rx_bandwidth(E3XX_DEFAULT_BANDWIDTH, chan); + _ad9361->set_dc_offset_auto(rx_fe, E3XX_DEFAULT_AUTO_DC_OFFSET); + _ad9361->set_iq_balance_auto(rx_fe, E3XX_DEFAULT_AUTO_IQ_BALANCE); + _ad9361->set_agc(rx_fe, E3XX_DEFAULT_AGC_ENABLE); std::string tx_fe = get_which_ad9361_chain(TX_DIRECTION, chan); - this->set_tx_gain(NEON_DEFAULT_GAIN, chan); - this->set_tx_frequency(NEON_DEFAULT_FREQ, chan); - this->set_tx_bandwidth(NEON_DEFAULT_BANDWIDTH, chan); + this->set_tx_gain(E3XX_DEFAULT_GAIN, chan); + this->set_tx_frequency(E3XX_DEFAULT_FREQ, chan); + this->set_tx_bandwidth(E3XX_DEFAULT_BANDWIDTH, chan); } } -void neon_radio_ctrl_impl::_init_mpm_sensors(const direction_t dir, const size_t chan_idx) +void e3xx_radio_ctrl_impl::_init_mpm_sensors(const direction_t dir, const size_t chan_idx) { const std::string trx = (dir == RX_DIRECTION) ? "RX" : "TX"; const fs_path fe_path = fs_path("dboards") / _radio_slot diff --git a/host/lib/usrp/dboard/neon/CMakeLists.txt b/host/lib/usrp/dboard/neon/CMakeLists.txt deleted file mode 100644 index a2473bd0a..000000000 --- a/host/lib/usrp/dboard/neon/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -# -# Copyright 2018 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -if(ENABLE_E320) - list(APPEND NEON_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/neon_radio_ctrl_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/neon_radio_ctrl_init.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/neon_ad9361_iface.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/neon_bands.cpp - ) - LIBUHD_APPEND_SOURCES(${NEON_SOURCES}) -endif(ENABLE_E320) diff --git a/host/lib/usrp/dboard/neon/neon_ad9361_iface.hpp b/host/lib/usrp/dboard/neon/neon_ad9361_iface.hpp deleted file mode 100644 index 1b7a48142..000000000 --- a/host/lib/usrp/dboard/neon/neon_ad9361_iface.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_LIBUHD_RFNOC_NEON_AD9361_IFACE_HPP -#define INCLUDED_LIBUHD_RFNOC_NEON_AD9361_IFACE_HPP - -#include <uhd/types/direction.hpp> -#include <uhd/types/filters.hpp> -#include <uhd/types/sensors.hpp> -#include <uhdlib/usrp/common/ad9361_ctrl.hpp> -#include <uhdlib/utils/rpc.hpp> -#include <memory> -#include <string> -#include <vector> - -using namespace uhd; -using namespace uhd::usrp; - -ad9361_ctrl::sptr make_rpc(rpc_client::sptr rpcc); -std::string get_which_ad9361_chain(const direction_t dir, const size_t chan); - -#endif /* INCLUDED_LIBUHD_RFNOC_NEON_AD9361_IFACE_HPP */ diff --git a/host/lib/usrp/dboard/neon/neon_radio_ctrl_impl.cpp b/host/lib/usrp/dboard/neon/neon_radio_ctrl_impl.cpp deleted file mode 100644 index d8fabcee0..000000000 --- a/host/lib/usrp/dboard/neon/neon_radio_ctrl_impl.cpp +++ /dev/null @@ -1,563 +0,0 @@ -// -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "neon_radio_ctrl_impl.hpp" -#include "neon_constants.hpp" -#include "neon_regs.hpp" -#include <uhd/exception.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/transport/chdr.hpp> -#include <uhd/types/direction.hpp> -#include <uhd/types/eeprom.hpp> -#include <uhd/utils/algorithm.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/utils/math.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/format.hpp> -#include <boost/make_shared.hpp> -#include <cmath> -#include <cstdlib> -#include <sstream> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::rfnoc; -using namespace uhd::math::fp_compare; - -/****************************************************************************** - * Structors - *****************************************************************************/ -UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(neon_radio_ctrl) -{ - UHD_LOG_TRACE(unique_id(), "Entering neon_radio_ctrl_impl ctor..."); - const char radio_slot_name[1] = {'A'}; - _radio_slot = radio_slot_name[get_block_id().get_block_count()]; - UHD_LOG_TRACE(unique_id(), "Radio slot: " << _radio_slot); - _rpc_prefix = "db_0_"; - - _init_defaults(); - _init_peripherals(); - _init_prop_tree(); -} - -neon_radio_ctrl_impl::~neon_radio_ctrl_impl() -{ - UHD_LOG_TRACE(unique_id(), "neon_radio_ctrl_impl::dtor() "); -} - - -/****************************************************************************** - * API Calls - *****************************************************************************/ - -bool neon_radio_ctrl_impl::check_radio_config() -{ - // mapping of frontend to radio perif index - static const size_t FE0 = 0; - static const size_t FE1 = 1; - const size_t num_rx = - _is_streamer_active(RX_DIRECTION, FE0) + _is_streamer_active(RX_DIRECTION, FE1); - const size_t num_tx = - _is_streamer_active(TX_DIRECTION, FE0) + _is_streamer_active(TX_DIRECTION, FE1); - - // setup the active chains in the codec - if ((num_rx + num_tx) == 0) { - // Ensure at least one RX chain is enabled so AD9361 outputs a sample clock - this->set_streaming_mode(false, false, true, false); - } else { - this->set_streaming_mode(_is_streamer_active(TX_DIRECTION, FE0), - _is_streamer_active(TX_DIRECTION, FE1), - _is_streamer_active(RX_DIRECTION, FE0), - _is_streamer_active(RX_DIRECTION, FE1)); - } - return true; -} - -void neon_radio_ctrl_impl::set_streaming_mode( - const bool tx1, const bool tx2, const bool rx1, const bool rx2) -{ - UHD_LOG_TRACE(unique_id(), "Setting up streaming ...") - const size_t num_rx = rx1 + rx2; - const size_t num_tx = tx1 + tx2; - - // setup the active chains in the codec - _ad9361->set_active_chains(tx1, tx2, rx1, rx2); - - const std::string TIMING_MODE_2R2T = "2R2T"; - const std::string TIMING_MODE_1R1T = "1R1T"; - const std::string MIMO = "MIMO"; // 2R2T - const std::string SISO_TX1 = "SISO_TX1"; // 1R1T - const std::string SISO_TX0 = "SISO_TX0"; // 1R1T - // setup 1R1T/2R2T mode in catalina and fpga - // The Catalina interface in the fpga needs to know which TX channel to use for - // the data on the LVDS lines. - if ((num_rx == 2) or (num_tx == 2)) { - // AD9361 is in 2R2T mode - _ad9361->set_timing_mode(TIMING_MODE_2R2T); - this->set_channel_mode(MIMO); - } else { - // AD9361 is in 1R1T mode - _ad9361->set_timing_mode(TIMING_MODE_1R1T); - - // Set to SIS0_TX1 if we're using the second TX antenna, otherwise - // default to SISO_TX0 - this->set_channel_mode(tx2 ? SISO_TX1 : SISO_TX0); - } -} - -void neon_radio_ctrl_impl::set_channel_mode(const std::string& channel_mode) -{ - // MIMO for 2R2T mode for 2 channels - // SISO_TX1 for 1R1T mode for 1 channel - TX1 - // SISO_TX0 for 1R1T mode for 1 channel - TX0 - - _rpcc->request_with_token<void>("set_channel_mode", channel_mode); -} - -/* loopback_self_test checks the integrity of the FPGA->AD936x->FPGA sample interface. - The AD936x is put in loopback mode that sends the TX data unchanged to the RX side. - A test value is written to the codec_idle register in the TX side of the radio. - The readback register is then used to capture the values on the TX and RX sides - simultaneously for comparison. It is a reasonably effective test for AC timing - since I/Q Ch0/Ch1 alternate over the same wires. Note, however, that it uses - whatever timing is configured at the time the test is called rather than select - worst case conditions to stress the interface. - Note: This currently only tests 2R2T mode -*/ -void neon_radio_ctrl_impl::loopback_self_test( - std::function<void(uint32_t)> poker_functor, std::function<uint64_t()> peeker_functor) -{ - // Save current rate before running this test - const double current_rate = this->get_rate(); - // Set 2R2T mode, stream on all channels - this->set_streaming_mode(true, true, true, true); - // Set maximum rate for 2R2T mode - this->set_rate(30.72e6); - // Put AD936x in loopback mode - _ad9361->data_port_loopback(true); - UHD_LOG_INFO(unique_id(), "Performing CODEC loopback test... "); - size_t hash = size_t(time(NULL)); - constexpr size_t loopback_count = 100; - - // Allow some time for AD936x to enter loopback mode. - // There is no clear statement in the documentation of how long it takes, - // but UG-570 does say to "allow six ADC_CLK/64 clock cycles of flush time" - // when leaving the TX or RX states. That works out to ~75us at the - // minimum clock rate of 5 MHz, which lines up with test results. - // Sleeping 1ms is far more than enough. - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - - for (size_t i = 0; i < loopback_count; i++) { - // Create test word - boost::hash_combine(hash, i); - const uint32_t word32 = uint32_t(hash) & 0xfff0fff0; - // const uint32_t word32 = 0xCA00C100; - // Write test word to codec_idle idle register (on TX side) - poker_functor(word32); - - // Read back values - TX is lower 32-bits and RX is upper 32-bits - const uint64_t rb_word64 = peeker_functor(); - const uint32_t rb_tx = uint32_t(rb_word64 >> 32); - const uint32_t rb_rx = uint32_t(rb_word64 & 0xffffffff); - - // Compare TX and RX values to test word - bool test_fail = word32 != rb_tx or word32 != rb_rx; - if (test_fail) { - UHD_LOG_WARNING(unique_id(), - "CODEC loopback test failed! " - << boost::format("Expected: 0x%08X Received (TX/RX): 0x%08X/0x%08X") - % word32 % rb_tx % rb_rx); - throw uhd::runtime_error("CODEC loopback test failed."); - } - } - UHD_LOG_INFO(unique_id(), "CODEC loopback test passed"); - - // Zero out the idle data. - poker_functor(0); - - // Take AD936x out of loopback mode - _ad9361->data_port_loopback(false); - this->set_streaming_mode(true, false, true, false); - // Switch back to current rate - this->set_rate(current_rate); -} - -double neon_radio_ctrl_impl::set_rate(const double rate) -{ - std::lock_guard<std::mutex> l(_set_lock); - UHD_LOG_DEBUG(unique_id(), "Asking for clock rate " << rate / 1e6 << " MHz\n"); - double actual_tick_rate = _ad9361->set_clock_rate(rate); - UHD_LOG_DEBUG( - unique_id(), "Actual clock rate " << actual_tick_rate / 1e6 << " MHz\n"); - - radio_ctrl_impl::set_rate(rate); - return rate; -} - -void neon_radio_ctrl_impl::set_tx_antenna(const std::string& ant, const size_t chan) -{ - if (ant != get_tx_antenna(chan)) { - throw uhd::value_error( - str(boost::format("[%s] Requesting invalid TX antenna value: %s") - % unique_id() % ant)); - } - radio_ctrl_impl::set_tx_antenna(ant, chan); - // We can't actually set the TX antenna, so let's stop here. -} - -void neon_radio_ctrl_impl::set_rx_antenna(const std::string& ant, const size_t chan) -{ - UHD_ASSERT_THROW(chan <= NEON_NUM_CHANS); - if (std::find(NEON_RX_ANTENNAS.begin(), NEON_RX_ANTENNAS.end(), ant) - == NEON_RX_ANTENNAS.end()) { - throw uhd::value_error( - str(boost::format("[%s] Requesting invalid RX antenna value: %s") - % unique_id() % ant)); - } - UHD_LOG_TRACE(unique_id(), "Setting RX antenna to " << ant << " for chan " << chan); - - radio_ctrl_impl::set_rx_antenna(ant, chan); - _set_atr_bits(chan); -} - -double neon_radio_ctrl_impl::set_tx_frequency(const double freq, const size_t chan) -{ - UHD_LOG_TRACE(unique_id(), "set_tx_frequency(f=" << freq << ", chan=" << chan << ")"); - std::lock_guard<std::mutex> l(_set_lock); - - double clipped_freq = uhd::clip(freq, AD9361_TX_MIN_FREQ, AD9361_TX_MAX_FREQ); - - double coerced_freq = - _ad9361->tune(get_which_ad9361_chain(TX_DIRECTION, chan), clipped_freq); - radio_ctrl_impl::set_tx_frequency(coerced_freq, chan); - // Front-end switching - _set_atr_bits(chan); - - return coerced_freq; -} - -double neon_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t chan) -{ - UHD_LOG_TRACE(unique_id(), "set_rx_frequency(f=" << freq << ", chan=" << chan << ")"); - std::lock_guard<std::mutex> l(_set_lock); - - double clipped_freq = uhd::clip(freq, AD9361_RX_MIN_FREQ, AD9361_RX_MAX_FREQ); - - double coerced_freq = - _ad9361->tune(get_which_ad9361_chain(RX_DIRECTION, chan), clipped_freq); - radio_ctrl_impl::set_rx_frequency(coerced_freq, chan); - // Front-end switching - _set_atr_bits(chan); - - return coerced_freq; -} - -double neon_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan) -{ - std::lock_guard<std::mutex> l(_set_lock); - double clipped_bw = - _ad9361->set_bw_filter(get_which_ad9361_chain(RX_DIRECTION, chan), bandwidth); - return radio_ctrl_impl::set_rx_bandwidth(clipped_bw, chan); -} - -double neon_radio_ctrl_impl::set_tx_bandwidth(const double bandwidth, const size_t chan) -{ - std::lock_guard<std::mutex> l(_set_lock); - double clipped_bw = - _ad9361->set_bw_filter(get_which_ad9361_chain(TX_DIRECTION, chan), bandwidth); - return radio_ctrl_impl::set_tx_bandwidth(clipped_bw, chan); -} - -double neon_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan) -{ - std::lock_guard<std::mutex> l(_set_lock); - UHD_LOG_TRACE(unique_id(), "set_tx_gain(gain=" << gain << ", chan=" << chan << ")"); - double clip_gain = uhd::clip(gain, AD9361_MIN_TX_GAIN, AD9361_MAX_TX_GAIN); - _ad9361->set_gain(get_which_ad9361_chain(TX_DIRECTION, chan), clip_gain); - radio_ctrl_impl::set_tx_gain(clip_gain, chan); - return clip_gain; -} - -double neon_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan) -{ - std::lock_guard<std::mutex> l(_set_lock); - UHD_LOG_TRACE(unique_id(), "set_rx_gain(gain=" << gain << ", chan=" << chan << ")"); - double clip_gain = uhd::clip(gain, AD9361_MIN_RX_GAIN, AD9361_MAX_RX_GAIN); - _ad9361->set_gain(get_which_ad9361_chain(RX_DIRECTION, chan), clip_gain); - radio_ctrl_impl::set_rx_gain(clip_gain, chan); - return clip_gain; -} - -size_t neon_radio_ctrl_impl::get_chan_from_dboard_fe( - const std::string& fe, const direction_t /* dir */ -) -{ - const size_t chan = boost::lexical_cast<size_t>(fe); - if (chan > _get_num_radios() - 1) { - UHD_LOG_WARNING(unique_id(), - boost::format("Invalid channel determined from dboard frontend %s.") % fe); - } - return chan; -} - -std::string neon_radio_ctrl_impl::get_dboard_fe_from_chan( - const size_t chan, const direction_t /* dir */ -) -{ - return std::to_string(chan); -} - -void neon_radio_ctrl_impl::set_rpc_client( - uhd::rpc_client::sptr rpcc, const uhd::device_addr_t& block_args) -{ - _rpcc = rpcc; - _block_args = block_args; - UHD_LOG_TRACE(unique_id(), "Instantiating AD9361 control object..."); - _ad9361 = make_rpc(_rpcc); - - UHD_LOG_TRACE(unique_id(), "Setting Catalina Defaults... "); - // Initialize catalina - this->_init_codec(); - - if (block_args.has_key("identify")) { - const std::string identify_val = block_args.get("identify"); - int identify_duration = std::atoi(identify_val.c_str()); - if (identify_duration == 0) { - identify_duration = 5; - } - UHD_LOG_INFO(unique_id(), - "Running LED identification process for " << identify_duration - << " seconds."); - _identify_with_leds(identify_duration); - } - // Note: MCR gets set during the init() call (prior to this), which takes - // in arguments from the device args. So if block_args contains a - // master_clock_rate key, then it should better be whatever the device is - // configured to do. - _master_clock_rate = - _rpcc->request_with_token<double>(_rpc_prefix + "get_master_clock_rate"); - if (block_args.cast<double>("master_clock_rate", _master_clock_rate) - != _master_clock_rate) { - throw uhd::runtime_error(str( - boost::format("Master clock rate mismatch. Device returns %f MHz, " - "but should have been %f MHz.") - % (_master_clock_rate / 1e6) - % (block_args.cast<double>("master_clock_rate", _master_clock_rate) / 1e6))); - } - UHD_LOG_DEBUG( - unique_id(), "Master Clock Rate is: " << (_master_clock_rate / 1e6) << " MHz."); - this->set_rate(_master_clock_rate); - - // Loopback test - for (size_t chan = 0; chan < _get_num_radios(); chan++) { - loopback_self_test( - [this, chan]( - const uint32_t value) { this->sr_write(regs::CODEC_IDLE, value, chan); }, - [this, chan]() { - return this->user_reg_read64(regs::RB_CODEC_READBACK, chan); - }); - } - - const size_t db_idx = get_block_id().get_block_count(); - _tree->access<eeprom_map_t>(_root_path / "eeprom") - .add_coerced_subscriber([this, db_idx](const eeprom_map_t& db_eeprom) { - this->_rpcc->notify_with_token("set_db_eeprom", db_idx, db_eeprom); - }) - .set_publisher([this, db_idx]() { - return this->_rpcc->request_with_token<eeprom_map_t>("get_db_eeprom", db_idx); - }); - - // Init sensors - for (const auto& dir : std::vector<direction_t>{RX_DIRECTION, TX_DIRECTION}) { - for (size_t chan_idx = 0; chan_idx < NEON_NUM_CHANS; chan_idx++) { - _init_mpm_sensors(dir, chan_idx); - } - } -} - -bool neon_radio_ctrl_impl::get_lo_lock_status(const direction_t dir) -{ - if (not(bool(_rpcc))) { - UHD_LOG_DEBUG(unique_id(), "Reported no LO lock due to lack of RPC connection."); - return false; - } - - const std::string trx = (dir == RX_DIRECTION) ? "rx" : "tx"; - bool lo_lock = - _rpcc->request_with_token<bool>(_rpc_prefix + "get_ad9361_lo_lock", trx); - UHD_LOG_TRACE(unique_id(), - "AD9361 " << trx << " LO reports lock: " << (lo_lock ? "Yes" : "No")); - - return lo_lock; -} - -void neon_radio_ctrl_impl::_set_atr_bits(const size_t chan) -{ - const auto rx_freq = radio_ctrl_impl::get_rx_frequency(chan); - const auto tx_freq = radio_ctrl_impl::get_tx_frequency(chan); - const auto rx_ant = radio_ctrl_impl::get_rx_antenna(chan); - const uint32_t rx_regs = _get_rx_switches(chan, rx_freq, rx_ant); - const uint32_t tx_regs = _get_tx_switches(chan, tx_freq); - const uint32_t idle_regs = TX_AMP_OFF << TX_AMP_SHIFT | TRX1_SW_TX_HB << TRX_SW_SHIFT - | TX_SW2_LB_80 << TX_SW2_SHIFT - | TX_SW1_LB_80 << TX_SW1_SHIFT | RX_SW3_OFF << RX_SW3_SHIFT - | RX_SW2_OFF << RX_SW2_SHIFT | RX_SW1_OFF << RX_SW1_SHIFT; - - _db_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_IDLE, idle_regs); - _db_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_RX_ONLY, rx_regs); - _db_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_TX_ONLY, tx_regs); - _db_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_FULL_DUPLEX, rx_regs | tx_regs); - - // The LED signal names are reversed, but are consistent with the schematic - const int idle_led = 0; - const bool is_txrx = rx_ant == "TX/RX"; - const int rx_led = 1 << TRX_LED_GRN_SHIFT; - const int tx_led = 1 << TX_LED_RED_SHIFT; - const int txrx_led = 1 << RX_LED_GRN_SHIFT; - - _leds_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_IDLE, idle_led); - _leds_gpio[chan]->set_atr_reg( - usrp::gpio_atr::ATR_REG_RX_ONLY, is_txrx ? txrx_led : rx_led); - _leds_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_TX_ONLY, tx_led); - _leds_gpio[chan]->set_atr_reg(usrp::gpio_atr::ATR_REG_FULL_DUPLEX, rx_led | tx_led); -} - -void neon_radio_ctrl_impl::_identify_with_leds(const int identify_duration) -{ - auto end_time = - std::chrono::steady_clock::now() + std::chrono::seconds(identify_duration); - bool led_state = true; - while (std::chrono::steady_clock::now() < end_time) { - // Add update_leds - led_state = !led_state; - std::this_thread::sleep_for(std::chrono::milliseconds(500)); - } -} - -uint32_t neon_radio_ctrl_impl::_get_tx_switches(const size_t chan, const double freq) -{ - UHD_LOG_TRACE( - unique_id(), "Update all TX freq related switches. f=" << freq << " Hz, "); - auto tx_sw1 = TX_SW1_LB_160; - auto tx_sw2 = TX_SW2_LB_160; - auto trx_sw = (chan == 0) ? TRX1_SW_TX_LB : TRX2_SW_TX_LB; - auto tx_amp = TX_AMP_LF_ON; - - const auto band = _map_freq_to_tx_band(freq); - switch (band) { - case tx_band::LB_80: - tx_sw1 = TX_SW1_LB_80; - tx_sw2 = TX_SW2_LB_80; - break; - case tx_band::LB_160: - tx_sw1 = TX_SW1_LB_160; - tx_sw2 = TX_SW2_LB_160; - break; - case tx_band::LB_225: - tx_sw1 = TX_SW1_LB_225; - tx_sw2 = TX_SW2_LB_225; - break; - case tx_band::LB_400: - tx_sw1 = TX_SW1_LB_400; - tx_sw2 = TX_SW2_LB_400; - break; - case tx_band::LB_575: - tx_sw1 = TX_SW1_LB_575; - tx_sw2 = TX_SW2_LB_575; - break; - case tx_band::LB_1000: - tx_sw1 = TX_SW1_LB_1000; - tx_sw2 = TX_SW2_LB_1000; - break; - case tx_band::LB_1700: - tx_sw1 = TX_SW1_LB_1700; - tx_sw2 = TX_SW2_LB_1700; - break; - case tx_band::LB_2750: - tx_sw1 = TX_SW1_LB_2750; - tx_sw2 = TX_SW2_LB_2750; - break; - case tx_band::HB: - trx_sw = (chan == 0) ? TRX1_SW_TX_HB : TRX2_SW_TX_HB; - tx_amp = TX_AMP_HF_ON; - break; - case tx_band::INVALID_BAND: - UHD_LOG_ERROR(unique_id(), "Cannot map TX frequency to band: " << freq); - UHD_THROW_INVALID_CODE_PATH(); - break; - } - - auto tx_regs = tx_amp << TX_AMP_SHIFT | trx_sw << TRX_SW_SHIFT - | tx_sw2 << TX_SW2_SHIFT | tx_sw1 << TX_SW1_SHIFT; - return tx_regs; -} - -uint32_t neon_radio_ctrl_impl::_get_rx_switches( - const size_t chan, const double freq, const std::string& ant) -{ - UHD_LOG_TRACE( - unique_id(), "Update all RX freq related switches. f=" << freq << " Hz, "); - // Default to OFF - auto rx_sw1 = RX_SW1_OFF; - auto rx_sw2 = RX_SW2_OFF; - auto rx_sw3 = RX_SW3_OFF; - auto trx_sw = (chan == 0) ? TRX1_SW_RX : TRX2_SW_RX; - if (ant == "TX/RX") { - rx_sw3 = RX_SW3_HBRX_LBTRX; - trx_sw = (chan == 0) ? TRX1_SW_RX : TRX2_SW_RX; - } else if (ant == "RX2") { - rx_sw3 = RX_SW3_HBTRX_LBRX; - // Set TRX switch to TX when receiving on RX2 - trx_sw = TRX1_SW_TX_HB; - } - - const auto band = _map_freq_to_rx_band(freq); - switch (band) { - case rx_band::LB_B2: - rx_sw1 = RX_SW1_LB_B2; - rx_sw2 = RX_SW2_LB_B2; - break; - case rx_band::LB_B3: - rx_sw1 = RX_SW1_LB_B3; - rx_sw2 = RX_SW2_LB_B3; - break; - case rx_band::LB_B4: - rx_sw1 = RX_SW1_LB_B4; - rx_sw2 = RX_SW2_LB_B4; - break; - case rx_band::LB_B5: - rx_sw1 = RX_SW1_LB_B5; - rx_sw2 = RX_SW2_LB_B5; - break; - case rx_band::LB_B6: - rx_sw1 = RX_SW1_LB_B6; - rx_sw2 = RX_SW2_LB_B6; - break; - case rx_band::LB_B7: - rx_sw1 = RX_SW1_LB_B7; - rx_sw2 = RX_SW2_LB_B7; - break; - case rx_band::HB: - rx_sw1 = RX_SW1_OFF; - rx_sw2 = RX_SW2_OFF; - if (ant == "TX/RX") { - rx_sw3 = RX_SW3_HBTRX_LBRX; - } else if (ant == "RX2") { - rx_sw3 = RX_SW3_HBRX_LBTRX; - } - break; - case rx_band::INVALID_BAND: - UHD_LOG_ERROR(unique_id(), "Cannot map RX frequency to band: " << freq); - UHD_THROW_INVALID_CODE_PATH(); - break; - } - - auto rx_regs = trx_sw << TRX_SW_SHIFT | rx_sw3 << RX_SW3_SHIFT - | rx_sw2 << RX_SW2_SHIFT | rx_sw1 << RX_SW1_SHIFT; - return rx_regs; -} - -UHD_RFNOC_BLOCK_REGISTER(neon_radio_ctrl, "NeonRadio"); diff --git a/host/lib/usrp/e300/CMakeLists.txt b/host/lib/usrp/e300/CMakeLists.txt deleted file mode 100644 index 9821fe34a..000000000 --- a/host/lib/usrp/e300/CMakeLists.txt +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright 2013-2015 Ettus Research LLC -# Copyright 2018 Ettus Research, a National Instruments Company -# -# SPDX-License-Identifier: GPL-3.0-or-later -# - -######################################################################## -# This file included, use CMake directory variables -######################################################################## - -######################################################################## -# Conditionally configure the USRP-E300 support -######################################################################## -find_package(UDev) - -if(ENABLE_E300) - list(APPEND E300_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/e300_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_io_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_fifo_config.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_sysfs_hooks.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_network.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_global_regs.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_spi.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_sensor_manager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_i2c.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_eeprom_manager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_common.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_remote_codec_ctrl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e3xx_radio_ctrl_impl.cpp - ) - LIBUHD_APPEND_SOURCES(${E300_SOURCES}) - if(UDEV_FOUND AND NOT E300_FORCE_NETWORK) - include_directories(${UDEV_INCLUDE_DIR}) - LIBUHD_APPEND_LIBS(${UDEV_LIBS}) - set_source_files_properties( - ${E300_SOURCES} - PROPERTIES COMPILE_DEFINITIONS "E300_NATIVE=1" - ) - endif(UDEV_FOUND AND NOT E300_FORCE_NETWORK) - - if(ENABLE_GPSD) - set_source_files_properties( - ${CMAKE_CURRENT_SOURCE_DIR}/e300_impl.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/e300_impl.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/e3xx_radio_ctrl_impl.cpp - PROPERTIES COMPILE_DEFINITIONS "E300_GPSD=1" - ) - endif(ENABLE_GPSD) -endif(ENABLE_E300) diff --git a/host/lib/usrp/e300/e300_common.cpp b/host/lib/usrp/e300/e300_common.cpp deleted file mode 100644 index cd52bb9d0..000000000 --- a/host/lib/usrp/e300/e300_common.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright 2014-2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// -#include <uhd/image_loader.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/utils/static.hpp> - -#include "e300_impl.hpp" -#include "e300_fifo_config.hpp" -#include "e300_fifo_config.hpp" - -#include "e300_common.hpp" - -#include <boost/filesystem.hpp> -#include <fstream> -#include <string> - -#ifdef E300_NATIVE -namespace uhd { namespace usrp { namespace e300 { - -namespace common { - -void load_fpga_image(const std::string &path) -{ - if (not boost::filesystem::exists("/dev/xdevcfg")) - ::system("mknod /dev/xdevcfg c 259 0"); - - UHD_LOGGER_INFO("E300") << "Loading FPGA image: " << path << "..."; - - std::ifstream fpga_file(path.c_str(), std::ios_base::binary); - UHD_ASSERT_THROW(fpga_file.good()); - - std::FILE *wfile; - wfile = std::fopen("/dev/xdevcfg", "wb"); - UHD_ASSERT_THROW(!(wfile == NULL)); - - char buff[16384]; // devcfg driver can't handle huge writes - do { - fpga_file.read(buff, sizeof(buff)); - std::fwrite(buff, 1, size_t(fpga_file.gcount()), wfile); - } while (fpga_file); - - fpga_file.close(); - std::fclose(wfile); - - UHD_LOGGER_INFO("E300") << "FPGA image loaded"; -} - -static bool e300_image_loader(const image_loader::image_loader_args_t &image_loader_args) { - // Make sure this is an E3x0 and we don't want to use anything connected - uhd::device_addrs_t devs = e300_find(image_loader_args.args); - if(devs.size() == 0 or !image_loader_args.load_fpga) return false; - - std::string fpga_filename, idle_image; // idle_image never used, just needed for function - if(image_loader_args.fpga_path == "") { - get_e3x0_fpga_images(devs[0], fpga_filename, idle_image); - } - else { - if(not boost::filesystem::exists(image_loader_args.fpga_path)) { - throw uhd::runtime_error(str(boost::format("The path \"%s\" does not exist.") - % image_loader_args.fpga_path)); - } - else fpga_filename = image_loader_args.fpga_path; - } - - load_fpga_image(fpga_filename); - return true; -} - -UHD_STATIC_BLOCK(register_e300_image_loader) { - std::string recovery_instructions = "The default FPGA image will be loaded the next " - "time UHD uses this device."; - - image_loader::register_image_loader("e3x0", e300_image_loader, recovery_instructions); -} - -} - -}}} - -#else -namespace uhd { namespace usrp { namespace e300 { - -namespace common { - -void load_fpga_image(const std::string&) -{ - throw uhd::assertion_error("load_fpga_image() !E300_NATIVE"); -} - -} - -}}} -#endif diff --git a/host/lib/usrp/e300/e300_common.hpp b/host/lib/usrp/e300/e300_common.hpp deleted file mode 100644 index 8624f0e3c..000000000 --- a/host/lib/usrp/e300/e300_common.hpp +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_COMMON_HPP -#define INCLUDED_E300_COMMON_HPP - -namespace uhd { namespace usrp { namespace e300 { - -namespace common { - -void load_fpga_image(const std::string &path); - -}; - -}}} - -#endif // INCLUDED_E300_COMMON_HPP diff --git a/host/lib/usrp/e300/e300_defaults.hpp b/host/lib/usrp/e300/e300_defaults.hpp deleted file mode 100644 index 97b0ddc3f..000000000 --- a/host/lib/usrp/e300/e300_defaults.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_DEFAULTS_HPP -#define INCLUDED_E300_DEFAULTS_HPP - -#include "ad9361_client.h" - -namespace uhd { namespace usrp { namespace e300 { - -static const double DEFAULT_TICK_RATE = 32e6; -static const double MIN_TICK_RATE = 10e6; - -static const double DEFAULT_TX_SAMP_RATE = 1.0e6; -static const double DEFAULT_RX_SAMP_RATE = 1.0e6; -static const double DEFAULT_DDC_FREQ = 0.0; -static const double DEFAULT_DUC_FREQ = 0.0; - -static const std::string DEFAULT_TIME_SRC = "internal"; -static const std::string DEFAULT_CLOCK_SRC = "internal"; - -static const size_t DEFAULT_RX_DATA_FRAME_SIZE = 4096; -static const size_t DEFAULT_RX_DATA_NUM_FRAMES = 32; - -static const size_t DEFAULT_TX_DATA_FRAME_SIZE = 4096; -static const size_t DEFAULT_TX_DATA_NUM_FRAMES = 32; - -static const size_t DEFAULT_CTRL_FRAME_SIZE = 64; -static const size_t DEFAULT_CTRL_NUM_FRAMES = 32; - -static const size_t MAX_NET_RX_DATA_FRAME_SIZE = 1200; -static const size_t MAX_NET_TX_DATA_FRAME_SIZE = 1200; - -static const size_t MAX_AXI_RX_DATA_FRAME_SIZE = 4096; -static const size_t MAX_AXI_TX_DATA_FRAME_SIZE = 4096; - -static const size_t MAX_DMA_CHANNEL_PAIRS = 16; - -static const double AD9361_SPI_RATE = 8e6; - -class e300_ad9361_client_t : public ad9361_params { -public: - ~e300_ad9361_client_t() {} - double get_band_edge(frequency_band_t band) { - switch (band) { - case AD9361_RX_BAND0: return 1.2e9; - case AD9361_RX_BAND1: return 2.6e9; - case AD9361_TX_BAND0: return 2940.0e6; - default: return 0; - } - } - clocking_mode_t get_clocking_mode() { - return clocking_mode_t::AD9361_XTAL_N_CLK_PATH; - } - digital_interface_mode_t get_digital_interface_mode() { - return AD9361_DDR_FDD_LVCMOS; - } - digital_interface_delays_t get_digital_interface_timing() { - digital_interface_delays_t delays; - delays.rx_clk_delay = 0; - delays.rx_data_delay = 0xF; - delays.tx_clk_delay = 0; - delays.tx_data_delay = 0xF; - return delays; - } -}; - -}}} // namespace - -#endif // INCLUDED_E300_DEFAULTS_HPP diff --git a/host/lib/usrp/e300/e300_eeprom_manager.cpp b/host/lib/usrp/e300/e300_eeprom_manager.cpp deleted file mode 100644 index 6547048ec..000000000 --- a/host/lib/usrp/e300/e300_eeprom_manager.cpp +++ /dev/null @@ -1,241 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "e300_eeprom_manager.hpp" -#include <uhd/types/mac_addr.hpp> -#include <uhd/utils/byteswap.hpp> - -namespace uhd { namespace usrp { namespace e300 { - -static const std::string _bytes_to_string(const uint8_t* bytes, size_t max_len) -{ - std::string out; - for (size_t i = 0; i < max_len; i++) { - if (bytes[i] < 32 or bytes[i] > 127) return out; - out += bytes[i]; - } - return out; -} - -static void _string_to_bytes(const std::string &string, size_t max_len, uint8_t* buffer) -{ - byte_vector_t bytes; - const size_t len = std::min(string.size(), max_len); - for (size_t i = 0; i < len; i++){ - buffer[i] = string[i]; - } - if (len < max_len) - buffer[len] = '\0'; -} - -e300_eeprom_manager::e300_eeprom_manager(i2c::sptr i2c) : _i2c(i2c) -{ - read_mb_eeprom(); - read_db_eeprom(); -} - -e300_eeprom_manager::~e300_eeprom_manager(void) -{ -} - -const mboard_eeprom_t& e300_eeprom_manager::read_mb_eeprom(void) -{ - boost::mutex::scoped_lock(_mutex); - - std::vector<uint8_t> bytes; - bytes.resize(sizeof(mb_eeprom_map_t)); - mb_eeprom_map_t *map_ptr = reinterpret_cast<mb_eeprom_map_t*>(&bytes[0]); - memset(map_ptr, 0xff, sizeof(mb_eeprom_map_t)); - - // get the old contents - for(size_t i = 0; i < sizeof(mb_eeprom_map_t); i++) - bytes[i] = _i2c->get_i2c_reg8(MB_ADDR, i); - - mb_eeprom_map_t &map = *map_ptr; - - _mb_eeprom["product"] = std::to_string( - uhd::ntohx<uint16_t>(map.hw_product)); - _mb_eeprom["revision"] = std::to_string( - uhd::ntohx<uint16_t>(map.hw_revision)); - _mb_eeprom["serial"] = _bytes_to_string( - map.serial, MB_SERIAL_LEN); - - byte_vector_t mac_addr(map.mac_addr, map.mac_addr + 6); - _mb_eeprom["mac-addr"] = mac_addr_t::from_bytes(mac_addr).to_string(); - - _mb_eeprom["name"] = _bytes_to_string( - map.user_name, MB_NAME_LEN); - - return _mb_eeprom; -} - -const dboard_eeprom_t& e300_eeprom_manager::read_db_eeprom(void) -{ - boost::mutex::scoped_lock(_mutex); - - std::vector<uint8_t> bytes; - bytes.resize(sizeof(db_eeprom_map_t)); - db_eeprom_map_t *map_ptr = reinterpret_cast<db_eeprom_map_t*>(&bytes[0]); - memset(map_ptr, 0xff, sizeof(db_eeprom_map_t)); - - // get the old contents - for(size_t i = 0; i < sizeof(db_eeprom_map_t); i++) - bytes[i] = _i2c->get_i2c_reg16(DB_ADDR, i); - - db_eeprom_map_t &map = *map_ptr; - - _db_eeprom.id = uhd::usrp::dboard_id_t::from_uint16( - uhd::ntohx<uint16_t>(map.hw_product)); - - _db_eeprom.revision = std::to_string( - uhd::ntohx<uint16_t>(map.hw_revision)); - _db_eeprom.serial = _bytes_to_string( - map.serial, DB_SERIAL_LEN); - - return _db_eeprom; -} - -void e300_eeprom_manager::write_db_eeprom(const dboard_eeprom_t& eeprom) -{ - boost::mutex::scoped_lock(_mutex); - _db_eeprom = eeprom; - std::vector<uint8_t> bytes; - bytes.resize(sizeof(db_eeprom_map_t)); - - - db_eeprom_map_t *map_ptr = reinterpret_cast<db_eeprom_map_t*>(&bytes[0]); - memset(map_ptr, 0xff, sizeof(db_eeprom_map_t)); - - // get the old contents - for(size_t i = 0; i < sizeof(db_eeprom_map_t); i++) - bytes[i] = _i2c->get_i2c_reg16(DB_ADDR, i); - - db_eeprom_map_t &map = *map_ptr; - - // set the data version, that can be used to distinguish eeprom layouts - map.data_version_major = E310_DB_MAP_MAJOR; - map.data_version_minor = E310_DB_MAP_MINOR; - - if (_db_eeprom.id != dboard_id_t::none()) { - map.hw_product = uhd::htonx<uint16_t>( - _db_eeprom.id.to_uint16()); - } - - if (not _db_eeprom.revision.empty()) { - map.hw_revision = uhd::htonx<uint16_t>( - boost::lexical_cast<uint16_t>(_db_eeprom.revision)); - } - - if (not _db_eeprom.serial.empty()) { - _string_to_bytes(_db_eeprom.serial, DB_SERIAL_LEN, map.serial); - } - for(size_t i = 0; i < sizeof(mb_eeprom_map_t); i++) - _i2c->set_i2c_reg16(DB_ADDR, i, bytes[i]); -} - -void e300_eeprom_manager::write_mb_eeprom(const mboard_eeprom_t& eeprom) -{ - boost::mutex::scoped_lock(_mutex); - _mb_eeprom = eeprom; - std::vector<uint8_t> bytes; - bytes.resize(sizeof(mb_eeprom_map_t)); - - - mb_eeprom_map_t *map_ptr = reinterpret_cast<mb_eeprom_map_t*>(&bytes[0]); - memset(map_ptr, 0xff, sizeof(mb_eeprom_map_t)); - - // get the old contents - for(size_t i = 0; i < sizeof(mb_eeprom_map_t); i++) - bytes[i] = _i2c->get_i2c_reg8(MB_ADDR, i); - - mb_eeprom_map_t &map = *map_ptr; - - // set the data version, that can be used to distinguish eeprom layouts - map.data_version_major = E310_MB_MAP_MAJOR; - map.data_version_minor = E310_MB_MAP_MINOR; - - - if (_mb_eeprom.has_key("product")) { - map.hw_product = uhd::htonx<uint16_t>( - boost::lexical_cast<uint16_t>(_mb_eeprom["product"])); - } - if (_mb_eeprom.has_key("revision")) { - map.hw_revision = uhd::htonx<uint16_t>( - boost::lexical_cast<uint16_t>(_mb_eeprom["revision"])); - } - if (_mb_eeprom.has_key("serial")) { - _string_to_bytes(_mb_eeprom["serial"], MB_SERIAL_LEN, map.serial); - } - if (_mb_eeprom.has_key("mac-addr")) { - byte_vector_t mac_addr = mac_addr_t::from_string(_mb_eeprom["mac-addr"]).to_bytes(); - std::copy(mac_addr.begin(), mac_addr.end(), map.mac_addr); - } - - //store the name - if (_mb_eeprom.has_key("name")) { - _string_to_bytes(_mb_eeprom["name"], MB_NAME_LEN, map.user_name); - } - - for(size_t i = 0; i < sizeof(mb_eeprom_map_t); i++) - _i2c->set_i2c_reg8(MB_ADDR, i, bytes[i]); - -} - -e300_eeprom_manager::mboard_t e300_eeprom_manager::get_mb_type(void) const -{ - boost::mutex::scoped_lock(_mutex); - uint16_t pid = boost::lexical_cast<uint16_t>( - _mb_eeprom["product"]); - return get_mb_type(pid); -} - -e300_eeprom_manager::mboard_t e300_eeprom_manager::get_mb_type( - uint16_t pid) -{ - switch (pid) { - case E300_MB_PID: - return USRP_E300_MB; - - case E310_SG1_MB_PID: - return USRP_E310_SG1_MB; - - case E310_SG3_MB_PID: - return USRP_E310_SG3_MB; - - default: - return UNKNOWN; - }; -} - - -std::string e300_eeprom_manager::get_mb_type_string(void) const -{ - boost::mutex::scoped_lock(_mutex); - uint16_t product = boost::lexical_cast<uint16_t>( - _mb_eeprom["product"]); - switch (product) { - case E300_MB_PID: - return "E3XX"; - - case E310_SG1_MB_PID: - return "E3XX SG1"; - - case E310_SG3_MB_PID: - return "E3XX SG3"; - - default: - return "UNKNOWN"; - }; -} - -i2c::sptr e300_eeprom_manager::get_i2c_sptr(void) -{ - return _i2c; -} - - -}}} // namespace diff --git a/host/lib/usrp/e300/e300_eeprom_manager.hpp b/host/lib/usrp/e300/e300_eeprom_manager.hpp deleted file mode 100644 index ee4497211..000000000 --- a/host/lib/usrp/e300/e300_eeprom_manager.hpp +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_EEPROM_MANAGER_HPP -#define INCLUDED_E300_EEPROM_MANAGER_HPP - -#include <boost/thread/mutex.hpp> -#include <boost/shared_ptr.hpp> -#include <uhd/types/dict.hpp> -#include <uhd/usrp/mboard_eeprom.hpp> -#include <uhd/usrp/dboard_eeprom.hpp> - -#include "e300_i2c.hpp" - -namespace uhd { namespace usrp { namespace e300 { - -static const uint16_t E300_MB_PID = 0x77d1; -static const uint16_t E310_SG1_MB_PID = 0x77d2; -static const uint16_t E310_SG3_MB_PID = 0x77d3; - -static const uint16_t E300_DB_PID = 0x0100; -static const uint16_t E310_DB_PID = 0x0110; - -static const uint16_t E310_MB_MAP_MAJOR = 0x0001; -static const uint16_t E310_MB_MAP_MINOR = 0x0000; - -static const uint16_t E310_DB_MAP_MAJOR = 0x0001; -static const uint16_t E310_DB_MAP_MINOR = 0x0000; - -class e300_eeprom_manager : uhd::noncopyable -{ -public: - typedef boost::shared_ptr<e300_eeprom_manager> sptr; - e300_eeprom_manager(i2c::sptr i2c); - ~e300_eeprom_manager(); - - // mboard - const mboard_eeprom_t& read_mb_eeprom(); - void write_mb_eeprom(const mboard_eeprom_t& eeprom); - - UHD_INLINE const mboard_eeprom_t& get_mb_eeprom() - { - return _mb_eeprom; - } - - // dboard - const dboard_eeprom_t& read_db_eeprom(); - void write_db_eeprom(const dboard_eeprom_t& eeprom); - - UHD_INLINE const dboard_eeprom_t& get_db_eeprom() - { - return _db_eeprom; - } - - - i2c::sptr get_i2c_sptr(void); - - enum mboard_t {USRP_E300_MB, USRP_E310_SG1_MB, USRP_E310_SG3_MB, UNKNOWN}; - - mboard_t get_mb_type(void) const; - static mboard_t get_mb_type(uint16_t pid); - std::string get_mb_type_string(void) const; - -private: // types - const static size_t MB_SERIAL_LEN = 8; - const static size_t MB_NAME_LEN = 32; - const static size_t MB_ADDR = 0x51; - - const static size_t DB_SERIAL_LEN = 8; - const static size_t DB_ADDR = 0x50; - - struct mb_eeprom_map_t - { - // Data format version - uint16_t data_version_major; - uint16_t data_version_minor; - - // NIC mac address - uint8_t mac_addr[6]; - - // HW identification info - uint16_t hw_product; - uint16_t hw_revision; - - // serial - uint8_t serial[MB_SERIAL_LEN]; - uint8_t pad[20 - MB_SERIAL_LEN]; - - //User specific - uint8_t user_name[MB_NAME_LEN]; - }; - - struct db_eeprom_map_t - { - // Data format version - uint16_t data_version_major; - uint16_t data_version_minor; - - // HW identification info - uint16_t hw_product; - uint16_t hw_revision; - - // serial - uint8_t serial[DB_SERIAL_LEN]; - uint8_t pad[20 - DB_SERIAL_LEN]; - }; - -private: // members - mboard_eeprom_t _mb_eeprom; - dboard_eeprom_t _db_eeprom; - i2c::sptr _i2c; - - boost::mutex _mutex; -}; - -}}} //namespace - -#endif // INCLUDED_E300_EEPROM_MANAGER_HPP diff --git a/host/lib/usrp/e300/e300_fifo_config.cpp b/host/lib/usrp/e300/e300_fifo_config.cpp deleted file mode 100644 index e34b56ed4..000000000 --- a/host/lib/usrp/e300/e300_fifo_config.cpp +++ /dev/null @@ -1,437 +0,0 @@ -// -// Copyright 2013-2017 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifdef E300_NATIVE - -#include <uhdlib/utils/system_time.hpp> -#include <uhd/config.hpp> -#include <stdint.h> -#include <atomic> -#include <chrono> -#include <thread> - -// constants coded into the fpga parameters -static const size_t ZF_CONFIG_BASE = 0x40000000; -static const size_t ZF_PAGE_WIDTH = 10; -static const size_t H2S_STREAMS_WIDTH = 4; -static const size_t H2S_CMDFIFO_DEPTH = 5; -static const size_t S2H_STREAMS_WIDTH = 4; -static const size_t S2H_CMDFIFO_DEPTH = 5; - -// calculate more useful constants for this module -static const size_t ZF_PAGE_SIZE(1 << ZF_PAGE_WIDTH); -static const size_t H2S_NUM_STREAMS(1 << H2S_STREAMS_WIDTH); -static const size_t H2S_NUM_CMDS(1 << H2S_CMDFIFO_DEPTH); -static const size_t S2H_NUM_STREAMS(1 << S2H_STREAMS_WIDTH); -static const size_t S2H_NUM_CMDS(1 << S2H_CMDFIFO_DEPTH); - -//offsetsinto the arbiter memory map -static const size_t ARBITER_WR_CLEAR = 0; -static const size_t ARBITER_RD_SIG = 0; -static const size_t ARBITER_WR_ADDR = 4; -static const size_t ARBITER_WR_SIZE = 8; -static const size_t ARBITER_WR_STS_RDY = 12; -static const size_t ARBITER_WR_STS = 16; -static const size_t ARBITER_RB_STATUS = 16; -static const size_t ARBITER_RB_STATUS_OCC = 20; -static const size_t ARBITER_RB_ADDR_SPACE = 24; -static const size_t ARBITER_RB_SIZE_SPACE = 28; - -// registers for the wb32_iface -static const size_t SR_CORE_READBACK = 0; - - -static UHD_INLINE size_t S2H_BASE(const size_t base) -{ - return base + ZF_PAGE_SIZE * 0; -} - -static UHD_INLINE size_t H2S_BASE(const size_t base) -{ - return base + ZF_PAGE_SIZE * 1; -} - -static UHD_INLINE size_t REG_BASE(const size_t base) -{ - return base + ZF_PAGE_SIZE * 2; -} - -static UHD_INLINE size_t DST_BASE(const size_t base) -{ - return base + ZF_PAGE_SIZE * 3; -} - -static UHD_INLINE size_t ZF_STREAM_OFF(const size_t which) -{ - return which * 32; -} - -#include "e300_fifo_config.hpp" -#include <sys/mman.h> //mmap -#include <fcntl.h> //open, close -#include <poll.h> //poll -#include <uhd/utils/log.hpp> - -#include <boost/format.hpp> -#include <boost/thread/thread.hpp> //sleep -#include <uhd/types/time_spec.hpp> //timeout -#include <uhd/utils/log.hpp> -#include <uhdlib/utils/atomic.hpp> - -//locking stuff for shared irq -#include <boost/thread/mutex.hpp> -#include <boost/thread/condition_variable.hpp> - -struct e300_fifo_poll_waiter -{ - e300_fifo_poll_waiter(const int fd): - _fd(fd), - _poll_claimed(false) - { - //NOP - } - - /*! - * Waits until the file descriptor fd has data to read. - * Access to the file descriptor is thread safe. - */ - void wait(const double timeout) - { - if (timeout == 0) { - return; - } - - boost::mutex::scoped_lock l(_mutex); - if (_poll_claimed) - { - _cond.timed_wait(l, boost::posix_time::microseconds(long(timeout*1000000))); - } - else - { - _poll_claimed = true; - l.unlock(); - struct pollfd fds[1]; - fds[0].fd = _fd; - fds[0].events = POLLIN; - ::poll(fds, 1, long(timeout*1000)); - if (fds[0].revents & POLLIN) - ::read(_fd, NULL, 0); - - l.lock(); - _poll_claimed = 0; - _cond.notify_all(); - } - } - - boost::condition_variable _cond; - boost::mutex _mutex; - int _fd; - bool _poll_claimed; -}; - -static const size_t DEFAULT_FRAME_SIZE = 2048; -static const size_t DEFAULT_NUM_FRAMES = 32; - -using namespace uhd; -using namespace uhd::transport; - -struct __mem_addrz_t -{ - size_t which, phys, data, ctrl; -}; - -/*********************************************************************** - * peek n' poke mmapped space - **********************************************************************/ -UHD_INLINE void zf_poke32(const uint32_t addr, const uint32_t data) -{ - volatile uint32_t *p = reinterpret_cast<uint32_t *>(addr); - *p = data; -} - -UHD_INLINE uint32_t zf_peek32(const uint32_t addr) -{ - volatile const uint32_t *p = reinterpret_cast<const uint32_t *>(addr); - return *p; -} - -/*********************************************************************** - * managed buffer - **********************************************************************/ -struct e300_fifo_mb : managed_buffer -{ - e300_fifo_mb(const __mem_addrz_t &addrs, const size_t len): - ctrl_base(addrs.ctrl), phys_mem(addrs.phys), mem((void *)addrs.data), len(len){} - - void release(void) - { - UHD_ASSERT_THROW(zf_peek32(ctrl_base+ARBITER_RB_ADDR_SPACE) > 0); - UHD_ASSERT_THROW(zf_peek32(ctrl_base+ARBITER_RB_SIZE_SPACE) > 0); - zf_poke32(ctrl_base + ARBITER_WR_ADDR, phys_mem); - zf_poke32(ctrl_base + ARBITER_WR_SIZE, this->size()); - } - - template <typename T> - UHD_INLINE typename T::sptr get_new(void) - { - return make(reinterpret_cast<T *>(this), mem, len); - } - - const size_t ctrl_base; - const size_t phys_mem; - void *const mem; - const size_t len; -}; - -/*********************************************************************** - * transport - **********************************************************************/ -class e300_transport : public zero_copy_if -{ -public: - e300_transport( - boost::shared_ptr<void> allocator, - const __mem_addrz_t &addrs, - const size_t num_frames, - const size_t frame_size, - e300_fifo_poll_waiter *waiter, - const bool auto_release - ): - _allocator(allocator), - _addrs(addrs), - _num_frames(num_frames), - _frame_size(frame_size), - _index(0), - _waiter(waiter) - { - //UHD_LOGGER_INFO("E300") << boost::format("phys 0x%x") % addrs.phys ; - //UHD_LOGGER_INFO("E300") << boost::format("data 0x%x") % addrs.data ; - //UHD_LOGGER_INFO("E300") << boost::format("ctrl 0x%x") % addrs.ctrl ; - - const uint32_t sig = zf_peek32(_addrs.ctrl + ARBITER_RD_SIG); - UHD_ASSERT_THROW((sig >> 16) == 0xACE0); - - zf_poke32(_addrs.ctrl + ARBITER_WR_CLEAR, 1); - for (size_t i = 0; i < num_frames; i++) - { - //create a managed buffer at the given offset - __mem_addrz_t mb_addrs = addrs; - mb_addrs.phys += (i*frame_size); - mb_addrs.data += (i*frame_size); - boost::shared_ptr<e300_fifo_mb> mb(new e300_fifo_mb(mb_addrs, frame_size)); - - //setup the buffers so they are "positioned for use" - const size_t sts_good = (1 << 7) | (_addrs.which & 0xf); - if (auto_release) mb->get_new<managed_recv_buffer>(); //release for read - else zf_poke32(_addrs.ctrl + ARBITER_WR_STS, sts_good); //poke an ok into the sts fifo - - _buffs.push_back(mb); - } - } - - ~e300_transport(void) - { - //NOP - } - - template <typename T> - UHD_INLINE typename T::sptr get_buff(const double timeout) - { - const time_spec_t exit_time = uhd::get_system_time() + time_spec_t(timeout); - while (1) - { - if (zf_peek32(_addrs.ctrl + ARBITER_RB_STATUS_OCC)) - { - const uint32_t sts = zf_peek32(_addrs.ctrl + ARBITER_RB_STATUS); - UHD_ASSERT_THROW((sts >> 7) & 0x1); //assert OK - UHD_ASSERT_THROW((sts & 0xf) == _addrs.which); //expected tag - zf_poke32(_addrs.ctrl + ARBITER_WR_STS_RDY, 1); //pop from sts fifo - if (_index == _num_frames) - _index = 0; - return _buffs[_index++]->get_new<T>(); - } - if (uhd::get_system_time() > exit_time) { - break; - } - _waiter->wait(timeout); - //std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - - return typename T::sptr(); - } - - managed_recv_buffer::sptr get_recv_buff(const double timeout) - { - return this->get_buff<managed_recv_buffer>(timeout); - } - - size_t get_num_recv_frames(void) const - { - return _num_frames; - } - - size_t get_recv_frame_size(void) const - { - return _frame_size; - } - - managed_send_buffer::sptr get_send_buff(const double timeout) - { - return this->get_buff<managed_send_buffer>(timeout); - } - - size_t get_num_send_frames(void) const - { - return _num_frames; - } - - size_t get_send_frame_size(void) const - { - return _frame_size; - } - -private: - boost::shared_ptr<void> _allocator; - const __mem_addrz_t _addrs; - const size_t _num_frames; - const size_t _frame_size; - size_t _index; - e300_fifo_poll_waiter *_waiter; - std::vector<boost::shared_ptr<e300_fifo_mb> > _buffs; -}; - -/*********************************************************************** - * memory mapping - **********************************************************************/ -class e300_fifo_interface_impl : public virtual e300_fifo_interface -{ -public: - e300_fifo_interface_impl(const e300_fifo_config_t &config): - _config(config), - _bytes_in_use(0), - _recv_entries_in_use(std::vector<size_t>(S2H_NUM_STREAMS, 0)), - _send_entries_in_use(std::vector<size_t>(H2S_NUM_STREAMS, 0)) - { - //open the file descriptor to our kernel module - const std::string dev = "/dev/axi_fpga"; - _fd = ::open(dev.c_str(), O_RDWR|O_SYNC); - if (_fd < 0) - { - throw uhd::runtime_error("e300: failed to open " + dev); - } - - //mmap the control and data regions into virtual space - //UHD_VAR(_config.ctrl_length); - //UHD_VAR(_config.buff_length); - //UHD_VAR(_config.phys_addr); - _buff = ::mmap(NULL, _config.ctrl_length + _config.buff_length, PROT_READ|PROT_WRITE, MAP_SHARED, _fd, 0); - if (_buff == MAP_FAILED) - { - ::close(_fd); - throw uhd::runtime_error("e300: failed to mmap " + dev); - } - - //segment the memory according to zynq fifo arbiter - _ctrl_space = size_t(_buff); - _data_space = size_t(_buff) + _config.ctrl_length; - - //zero out the data region - std::memset((void *)_data_space, 0, _config.buff_length); - - //create a poll _waiter for the transports - _waiter = new e300_fifo_poll_waiter(_fd); - } - - virtual ~e300_fifo_interface_impl(void) - { - delete _waiter; - UHD_LOGGER_TRACE("E300")<< "cleanup: munmap" ; - ::munmap(_buff, _config.ctrl_length + _config.buff_length); - ::close(_fd); - } - - uhd::transport::zero_copy_if::sptr make_recv_xport( - const size_t which_stream, - const uhd::transport::zero_copy_xport_params ¶ms) - { - return this->_make_xport(which_stream, params, true); - } - - uhd::transport::zero_copy_if::sptr make_send_xport( - const size_t which_stream, - const uhd::transport::zero_copy_xport_params ¶ms) - { - return this->_make_xport(which_stream, params, false); - } - - size_t get_global_regs_base() const - { - return REG_BASE(_ctrl_space); - } - -private: - uhd::transport::zero_copy_if::sptr _make_xport( - const size_t which_stream, - const uhd::transport::zero_copy_xport_params ¶ms, - const bool is_recv) - { - boost::mutex::scoped_lock lock(_setup_mutex); - - const size_t frame_size = is_recv ? params.recv_frame_size : params.send_frame_size; - const size_t num_frames = is_recv ? params.num_recv_frames : params.num_send_frames; - size_t &entries_in_use = (is_recv)? _recv_entries_in_use.at(which_stream) - : _send_entries_in_use.at(which_stream); - - __mem_addrz_t addrs; - addrs.which = which_stream; - addrs.phys = _config.phys_addr + _bytes_in_use; - addrs.data = _data_space + _bytes_in_use; - addrs.ctrl = ((is_recv)? S2H_BASE(_ctrl_space) : H2S_BASE(_ctrl_space)) + ZF_STREAM_OFF(which_stream); - - uhd::transport::zero_copy_if::sptr xport; - if (is_recv) xport.reset(new e300_transport(shared_from_this(), addrs, num_frames, frame_size, _waiter, is_recv)); - else xport.reset(new e300_transport(shared_from_this(), addrs, num_frames, frame_size, _waiter, is_recv)); - - _bytes_in_use += num_frames*frame_size; - entries_in_use += num_frames; - - UHD_ASSERT_THROW(_recv_entries_in_use.at(which_stream) <= S2H_NUM_CMDS); - UHD_ASSERT_THROW(_send_entries_in_use.at(which_stream) <= H2S_NUM_CMDS); - UHD_ASSERT_THROW(_bytes_in_use <= _config.buff_length); - - - return xport; - } - - e300_fifo_config_t _config; - e300_fifo_poll_waiter *_waiter; - size_t _bytes_in_use; - int _fd; - void *_buff; - size_t _ctrl_space; - size_t _data_space; - std::vector<size_t> _recv_entries_in_use; - std::vector<size_t> _send_entries_in_use; - boost::mutex _setup_mutex; -}; - -e300_fifo_interface::sptr e300_fifo_interface::make(const e300_fifo_config_t &config) -{ - return e300_fifo_interface::sptr(new e300_fifo_interface_impl(config)); -} - -#else //E300_NATIVE - -#include "e300_fifo_config.hpp" -#include <uhd/exception.hpp> - -e300_fifo_interface::sptr e300_fifo_interface::make(const e300_fifo_config_t &) -{ - throw uhd::assertion_error("e300_fifo_interface::make() !E300_NATIVE"); -} - -#endif //E300_NATIVE diff --git a/host/lib/usrp/e300/e300_fifo_config.hpp b/host/lib/usrp/e300/e300_fifo_config.hpp deleted file mode 100644 index fa6b00eec..000000000 --- a/host/lib/usrp/e300/e300_fifo_config.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2013-2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_FIFO_CONFIG_HPP -#define INCLUDED_E300_FIFO_CONFIG_HPP - -#include <uhd/types/device_addr.hpp> -#include <uhd/types/wb_iface.hpp> -#include <uhd/transport/zero_copy.hpp> -#include <boost/enable_shared_from_this.hpp> - -struct e300_fifo_config_t -{ - size_t ctrl_length; - size_t buff_length; - size_t phys_addr; -}; - -e300_fifo_config_t e300_read_sysfs(void); -std::string e300_get_sysfs_attr(const std::string &node, const std::string &attr); - -struct e300_fifo_interface : boost::enable_shared_from_this<e300_fifo_interface> -{ - typedef boost::shared_ptr<e300_fifo_interface> sptr; - static sptr make(const e300_fifo_config_t &config); - - virtual uhd::transport::zero_copy_if::sptr make_recv_xport( - const size_t which_stream, - const uhd::transport::zero_copy_xport_params ¶ms) = 0; - - virtual uhd::transport::zero_copy_if::sptr make_send_xport( - const size_t which_stream, - const uhd::transport::zero_copy_xport_params &parms) = 0; - - virtual size_t get_global_regs_base(void) const = 0; -}; - -#endif /* INCLUDED_E300_FIFO_CONFIG_HPP */ diff --git a/host/lib/usrp/e300/e300_fpga_defs.hpp b/host/lib/usrp/e300/e300_fpga_defs.hpp deleted file mode 100644 index 517aa4653..000000000 --- a/host/lib/usrp/e300/e300_fpga_defs.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_FPGA_DEFS_HPP -#define INCLUDED_E300_FPGA_DEFS_HPP -namespace uhd { namespace usrp { namespace e300 { namespace fpga { - -static const size_t NUM_RADIOS = 2; - -static const uint32_t COMPAT_MAJOR = 255; -static const uint32_t COMPAT_MINOR = 0; - -}}}} // namespace - -#endif // INCLUDED_E300_FPGA_DEFS_HPP diff --git a/host/lib/usrp/e300/e300_global_regs.cpp b/host/lib/usrp/e300/e300_global_regs.cpp deleted file mode 100644 index ef607797a..000000000 --- a/host/lib/usrp/e300/e300_global_regs.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "e300_global_regs.hpp" - -#include <stdint.h> -#include <uhd/exception.hpp> -#include <uhd/utils/byteswap.hpp> -#include <cstring> -#include <iostream> - -namespace uhd { namespace usrp { namespace e300 { - -class global_regs_local_impl : public global_regs -{ -public: - global_regs_local_impl(const size_t ctrl_base) : _ctrl_base(ctrl_base) - { - } - - virtual ~global_regs_local_impl(void) - { - } - - uint32_t peek32(const uhd::wb_iface::wb_addr_type addr) - { - // setup readback register - _poke32(_ctrl_base + global_regs::SR_CORE_READBACK, addr); - return _peek32(_ctrl_base); - } - - void poke32(const uhd::wb_iface::wb_addr_type addr, const uint32_t data) - { - _poke32(_ctrl_base + static_cast<size_t>(addr), data); - } - - -private: - const size_t _ctrl_base; - - UHD_INLINE void _poke32(const uint32_t addr, const uint32_t data) - { - volatile uint32_t *p = reinterpret_cast<uint32_t *>(addr); - *p = data; - } - - UHD_INLINE uint32_t _peek32(const uint32_t addr) - { - volatile const uint32_t *p = reinterpret_cast<const uint32_t *>(addr); - return *p; - } -}; - -global_regs::sptr global_regs::make(const size_t ctrl_base) -{ - return sptr(new global_regs_local_impl(ctrl_base)); -} - -class global_regs_zc_impl : public global_regs -{ -public: - global_regs_zc_impl(uhd::transport::zero_copy_if::sptr xport) : _xport(xport) - { - } - - virtual ~global_regs_zc_impl(void) - { - } - - uint32_t peek32(const uhd::wb_iface::wb_addr_type addr) - { - global_regs_transaction_t transaction; - transaction.is_poke = uhd::htonx<uint32_t>(0); - transaction.addr = uhd::htonx<uint32_t>( - static_cast<uint32_t>(addr)); - { - uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw std::runtime_error("global_regs_zc_impl send timeout"); - std::memcpy(buff->cast<void *>(), &transaction, sizeof(transaction)); - buff->commit(sizeof(transaction)); - } - { - uhd::transport::managed_recv_buffer::sptr buff = _xport->get_recv_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw std::runtime_error("global_regs_zc_impl recv timeout"); - std::memcpy(&transaction, buff->cast<const void *>(), sizeof(transaction)); - } - return uhd::ntohx<uint32_t>(transaction.data); - } - - void poke32(const uhd::wb_iface::wb_addr_type addr, const uint32_t data) - { - global_regs_transaction_t transaction; - transaction.is_poke = uhd::htonx<uint32_t>(1); - transaction.addr = uhd::htonx<uint32_t>( - static_cast<uint32_t>(addr)); - transaction.data = uhd::htonx<uint32_t>(data); - { - uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw uhd::runtime_error("global_regs_zc_impl send timeout"); - std::memcpy(buff->cast<void *>(), &transaction, sizeof(transaction)); - buff->commit(sizeof(transaction)); - } - } - -private: - uhd::transport::zero_copy_if::sptr _xport; -}; - -global_regs::sptr global_regs::make(uhd::transport::zero_copy_if::sptr xport) -{ - return sptr(new global_regs_zc_impl(xport)); -} - -}}}; diff --git a/host/lib/usrp/e300/e300_global_regs.hpp b/host/lib/usrp/e300/e300_global_regs.hpp deleted file mode 100644 index e7d668d78..000000000 --- a/host/lib/usrp/e300/e300_global_regs.hpp +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_GLOBAL_REGS_HPP -#define INCLUDED_E300_GLOBAL_REGS_HPP - -#include <uhd/types/wb_iface.hpp> -#include <uhd/transport/zero_copy.hpp> - -namespace uhd { namespace usrp { namespace e300 { - -struct global_regs_transaction_t { - global_regs_transaction_t(): is_poke(0), addr(0), data(0), pad(0) {} - uint32_t is_poke; - uint32_t addr; - uint32_t data; - uint32_t pad; -}; - -class global_regs : uhd::noncopyable, public virtual uhd::wb_iface -{ -public: - typedef boost::shared_ptr<global_regs> sptr; - - static sptr make(const size_t ctrl_base); - static sptr make(uhd::transport::zero_copy_if::sptr xport); - - static const size_t SR_CORE_READBACK = 0; - static const size_t SR_CORE_MISC = 4; - static const size_t SR_CORE_TEST = 28; - static const size_t SR_CORE_XB_LOCAL = 32; - static const size_t SR_CORE_SPI_SEL = 64; - - // leave some room for registers, - // xbar starts with an offset of one - // 1K page. A part of which is used for - // DST_LOOKUP for DST_LOOKUP - - static const size_t SR_CORE_DST = 1024; - static const size_t SR_CORE_XBAR = 2048; - - static const size_t RB32_CORE_MISC = 1; - static const size_t RB32_CORE_COMPAT = 2; - static const size_t RB32_CORE_GITHASH = 3; - static const size_t RB32_CORE_PLL = 4; - static const size_t RB32_CORE_NUM_CE = 8; - static const size_t RB32_CORE_TEST = 24; - - // PPS selection - static const size_t PPS_GPS = 0; - static const size_t PPS_INT = 2; - static const size_t PPS_EXT = 3; -}; - -UHD_INLINE uint32_t XB_ADDR(const uint32_t addr) -{ - return global_regs::SR_CORE_XBAR + (addr << 2); -} - -UHD_INLINE uint32_t DST_ADDR(const uint32_t addr) -{ - return global_regs::SR_CORE_DST + (addr << 2); -} - -}}}; - -#endif /* INCLUDED_E300_GLOBAL_REGS_HPP */ diff --git a/host/lib/usrp/e300/e300_i2c.cpp b/host/lib/usrp/e300/e300_i2c.cpp deleted file mode 100644 index 24fd429b5..000000000 --- a/host/lib/usrp/e300/e300_i2c.cpp +++ /dev/null @@ -1,400 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "e300_i2c.hpp" -#include <uhd/exception.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/transport/udp_simple.hpp> - -#include <cstring> -#include <chrono> -#include <thread> - -namespace uhd { namespace usrp { namespace e300 { - -class zc_impl : public i2c -{ -public: - zc_impl(uhd::transport::zero_copy_if::sptr xport) : _xport(xport) - { - } - - virtual ~zc_impl(void) - { - } - - void set_i2c_reg8( - const uint8_t addr, - const uint8_t reg, - const uint8_t value) - { - i2c_transaction_t transaction; - transaction.type = WRITE | ONEBYTE; - transaction.addr = addr; - transaction.reg = uhd::htonx<uint16_t>(reg); - transaction.data = value; - { - uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw uhd::runtime_error("i2c_zc_impl send timeout"); - std::memcpy(buff->cast<void *>(), &transaction, sizeof(transaction)); - buff->commit(sizeof(transaction)); - } - } - - uint8_t get_i2c_reg8( - const uint8_t addr, - const uint8_t reg) - { - i2c_transaction_t transaction; - transaction.type = READ | ONEBYTE; - transaction.addr = addr; - transaction.reg = uhd::htonx<uint16_t>(reg); - { - uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw std::runtime_error("i2c_zc_impl send timeout"); - std::memcpy(buff->cast<void *>(), &transaction, sizeof(transaction)); - buff->commit(sizeof(transaction)); - } - { - uhd::transport::managed_recv_buffer::sptr buff = _xport->get_recv_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw std::runtime_error("i2c_zc_impl recv timeout"); - std::memcpy(&transaction, buff->cast<const void *>(), sizeof(transaction)); - } - return transaction.data; - } - - void set_i2c_reg16( - const uint8_t addr, - const uint16_t reg, - const uint8_t value) - { - i2c_transaction_t transaction; - transaction.type = WRITE | TWOBYTE; - transaction.addr = addr; - transaction.reg = uhd::htonx<uint16_t>(reg); - transaction.data = value; - { - uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw uhd::runtime_error("i2c_zc_impl send timeout"); - std::memcpy(buff->cast<void *>(), &transaction, sizeof(transaction)); - buff->commit(sizeof(transaction)); - } - } - - uint8_t get_i2c_reg16( - const uint8_t addr, - const uint16_t reg) - { - i2c_transaction_t transaction; - transaction.type = READ | TWOBYTE; - transaction.addr = addr; - transaction.reg = uhd::htonx<uint16_t>(reg); - { - uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw std::runtime_error("i2c_zc_impl send timeout"); - std::memcpy(buff->cast<void *>(), &transaction, sizeof(transaction)); - buff->commit(sizeof(transaction)); - } - { - uhd::transport::managed_recv_buffer::sptr buff = _xport->get_recv_buff(10.0); - if (not buff or buff->size() < sizeof(transaction)) - throw std::runtime_error("i2c_zc_impl recv timeout"); - std::memcpy(&transaction, buff->cast<const void *>(), sizeof(transaction)); - } - return transaction.data; - } - - -private: - uhd::transport::zero_copy_if::sptr _xport; -}; - -i2c::sptr i2c::make_zc(uhd::transport::zero_copy_if::sptr xport) -{ - return sptr(new zc_impl(xport)); -} - -class simple_udp_impl : public i2c -{ -public: - simple_udp_impl(const std::string &ip_addr, const std::string &port) - { - _xport = uhd::transport::udp_simple::make_connected(ip_addr, port); - } - - virtual ~simple_udp_impl(void) - { - } - - void set_i2c_reg8( - const uint8_t addr, - const uint8_t reg, - const uint8_t value) - { - i2c_transaction_t transaction; - transaction.type = i2c::WRITE | ONEBYTE; - transaction.addr = addr; - transaction.reg = uhd::htonx<uint16_t>(reg); - transaction.data = value; - - _xport->send( - boost::asio::buffer( - &transaction, - sizeof(transaction))); - } - - uint8_t get_i2c_reg8( - const uint8_t addr, - const uint8_t reg) - { - i2c_transaction_t transaction; - transaction.type = i2c::READ | ONEBYTE; - transaction.addr = addr; - transaction.reg = uhd::htonx<uint16_t>(reg); - transaction.data = 0; - - _xport->send( - boost::asio::buffer( - &transaction, - sizeof(transaction))); - - uint8_t buff[sizeof(i2c_transaction_t)] = {}; - const size_t nbytes = _xport->recv( - boost::asio::buffer(buff), 0.100); - if (not (nbytes == sizeof(transaction))) - throw std::runtime_error("i2c_simple_udp_impl recv timeout"); - i2c_transaction_t *reply = reinterpret_cast<i2c_transaction_t*>(buff); - return reply->data; - } - - void set_i2c_reg16( - const uint8_t addr, - const uint16_t reg, - const uint8_t value) - { - i2c_transaction_t transaction; - transaction.type = i2c::WRITE | TWOBYTE; - transaction.addr = addr; - transaction.reg = uhd::htonx<uint16_t>(reg); - transaction.data = value; - - _xport->send( - boost::asio::buffer( - &transaction, - sizeof(transaction))); - } - - uint8_t get_i2c_reg16( - const uint8_t addr, - const uint16_t reg) - { - i2c_transaction_t transaction; - transaction.type = i2c::READ | TWOBYTE; - transaction.addr = addr; - transaction.reg = uhd::htonx<uint16_t>(reg); - transaction.data = 0; - - _xport->send( - boost::asio::buffer( - &transaction, - sizeof(transaction))); - - uint8_t buff[sizeof(i2c_transaction_t)] = {}; - const size_t nbytes = _xport->recv( - boost::asio::buffer(buff), 0.100); - if (not (nbytes == sizeof(transaction))) - throw std::runtime_error("i2c_simple_udp_impl recv timeout"); - i2c_transaction_t *reply = reinterpret_cast<i2c_transaction_t*>(buff); - return reply->data; - } - -private: - uhd::transport::udp_simple::sptr _xport; -}; - -i2c::sptr i2c::make_simple_udp( - const std::string &ip_addr, - const std::string &port) -{ - return sptr(new simple_udp_impl(ip_addr,port)); -} - -}}} // namespace - -#ifdef E300_NATIVE - -#include <linux/i2c.h> -#include <linux/i2c-dev.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/ioctl.h> - -#include <boost/thread.hpp> -#include <stdint.h> - -namespace uhd { namespace usrp { namespace e300 { - -class i2cdev_impl : public i2c -{ -public: - i2cdev_impl(const std::string &device) - { - _fd = ::open(device.c_str(), O_RDWR); - if (_fd < 0) - throw uhd::system_error("open failed."); - } - - virtual ~i2cdev_impl(void) - { - close(_fd); - } - - void set_i2c_reg8( - const uint8_t addr, - const uint8_t reg, - const uint8_t value) - { - uint8_t outbuf[2]; - i2c_rdwr_ioctl_data packets; - i2c_msg messages[1]; - - messages[0].addr = addr; - messages[0].flags = 0; - messages[0].len = sizeof(outbuf); - messages[0].buf = outbuf; - - outbuf[0] = reg; - outbuf[1] = value; - - packets.msgs = messages; - packets.nmsgs = 1; - - if(::ioctl(_fd, I2C_RDWR, &packets) < 0) { - throw std::runtime_error("ioctl failed"); - } - // this is ugly - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - - uint8_t get_i2c_reg8( - const uint8_t addr, - const uint8_t reg) - { - i2c_rdwr_ioctl_data packets; - i2c_msg messages[2]; - - uint8_t outbuf = reg; - messages[0].addr = addr; - messages[0].flags = 0; - messages[0].len = sizeof(outbuf); - messages[0].buf = &outbuf; - - uint8_t inbuf; - messages[1].addr = addr; - messages[1].flags = I2C_M_RD; - messages[1].len = sizeof(inbuf); - messages[1].buf = &inbuf; - - packets.msgs = messages; - packets.nmsgs = 2; - - if(::ioctl(_fd, I2C_RDWR, &packets) < 0) { - throw std::runtime_error("ioctl failed."); - } - - return inbuf; - } - - // the daughterboard uses 16 bit addresses - void set_i2c_reg16( - const uint8_t addr, - const uint16_t reg, - const uint8_t value) - { - uint8_t outbuf[3]; - i2c_rdwr_ioctl_data packets; - i2c_msg messages[1]; - - messages[0].addr = addr; - messages[0].flags = 0; - messages[0].len = sizeof(outbuf); - messages[0].buf = outbuf; - - outbuf[0] = (reg >> 8) & 0xff; - outbuf[1] = reg & 0xff; - outbuf[2] = value; - - packets.msgs = messages; - packets.nmsgs = 1; - - if(::ioctl(_fd, I2C_RDWR, &packets) < 0) { - throw std::runtime_error("ioctl failed"); - } - // this is ugly - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - - - // the daughterboard eeprom uses 16 bit addresses - uint8_t get_i2c_reg16( - const uint8_t addr, - const uint16_t reg) - { - i2c_rdwr_ioctl_data packets; - i2c_msg messages[2]; - - // always little endian - uint8_t outbuf[2]; - outbuf[0] = (reg >> 8) & 0xff; - outbuf[1] = reg & 0xff; - - messages[0].addr = addr; - messages[0].flags = 0; - messages[0].len = sizeof(outbuf); - messages[0].buf = outbuf; - - uint8_t inbuf; - messages[1].addr = addr; - messages[1].flags = I2C_M_RD; - messages[1].len = sizeof(inbuf); - messages[1].buf = &inbuf; - - packets.msgs = messages; - packets.nmsgs = 2; - - if(::ioctl(_fd, I2C_RDWR, &packets) < 0) { - throw std::runtime_error("ioctl failed."); - } - - return inbuf; - } - -private: - int _fd; -}; - -}}} // namespace - -using namespace uhd::usrp::e300; - -i2c::sptr i2c::make_i2cdev(const std::string &device) -{ - return sptr(new i2cdev_impl(device)); -} -#else -using namespace uhd::usrp::e300; - -i2c::sptr i2c::make_i2cdev(const std::string &) -{ - throw uhd::assertion_error("i2c::make() !E300_NATIVE"); -} -#endif // E300_NATIVE diff --git a/host/lib/usrp/e300/e300_i2c.hpp b/host/lib/usrp/e300/e300_i2c.hpp deleted file mode 100644 index 1606d2146..000000000 --- a/host/lib/usrp/e300/e300_i2c.hpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_I2C_HPP -#define INCLUDED_E300_I2C_HPP - -#include <uhd/utils/noncopyable.hpp> -#include <stdint.h> -#include <boost/shared_ptr.hpp> - -#include <uhd/transport/zero_copy.hpp> - -namespace uhd { namespace usrp { namespace e300 { - -struct i2c_transaction_t { - i2c_transaction_t(): reg(0), addr(0), data(0), type(0) {}; - uint16_t reg; - uint8_t addr; - uint8_t data; - uint8_t type; -}; - -class i2c : public uhd::noncopyable -{ -public: - typedef boost::shared_ptr<i2c> sptr; - - static sptr make_i2cdev(const std::string &device); - static sptr make_zc(uhd::transport::zero_copy_if::sptr xport); - static sptr make_simple_udp( - const std::string &ip_addr, - const std::string &port); - - virtual uint8_t get_i2c_reg8( - const uint8_t addr, - const uint8_t reg) = 0; - - virtual uint8_t get_i2c_reg16( - const uint8_t addr, - const uint16_t reg) = 0; - - virtual void set_i2c_reg8( - const uint8_t addr, - const uint8_t reg, - const uint8_t value) = 0; - - virtual void set_i2c_reg16( - const uint8_t addr, - const uint16_t reg, - const uint8_t value) = 0; - - - static const uint8_t DB_EEPROM_ADDR = 0x50; - static const uint8_t MB_EEPROM_ADDR = 0x51; - - static const uint8_t WRITE = 0x1; - static const uint8_t READ = 0x0; - static const uint8_t TWOBYTE = 0x4; - static const uint8_t ONEBYTE = 0x2; -}; - -}}}; - -#endif // INCLUDED_E300_I2C_HPP diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp deleted file mode 100644 index 59a8cec88..000000000 --- a/host/lib/usrp/e300/e300_impl.cpp +++ /dev/null @@ -1,749 +0,0 @@ -// -// Copyright 2013-2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "e300_impl.hpp" -#include "e300_defaults.hpp" -#include "e300_fpga_defs.hpp" -#include "e300_spi.hpp" -#include "e300_regs.hpp" -#include "e300_eeprom_manager.hpp" -#include "e300_sensor_manager.hpp" -#include "e300_common.hpp" -#include "e300_remote_codec_ctrl.hpp" -#include "e3xx_radio_ctrl_impl.hpp" - - -#include <uhd/utils/log.hpp> -#include <uhd/utils/static.hpp> -#include <uhd/utils/paths.hpp> -#include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/transport/if_addrs.hpp> -#include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/transport/udp_simple.hpp> -#include <uhd/types/sensors.hpp> -#include <boost/make_shared.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/format.hpp> -#include <boost/filesystem.hpp> -#include <boost/functional/hash.hpp> -#include <boost/bind.hpp> -#include <boost/make_shared.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/thread/thread.hpp> //sleep -#include <boost/asio.hpp> -#include <fstream> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::usrp::gpio_atr; -using namespace uhd::transport; -namespace fs = boost::filesystem; -namespace asio = boost::asio; - -namespace uhd { namespace usrp { namespace e300 { - -/*********************************************************************** - * Discovery - **********************************************************************/ - -static std::vector<std::string> discover_ip_addrs( - const std::string& addr_hint, const std::string& port) -{ - std::vector<std::string> addrs; - - // Create a UDP transport to communicate: - // Some devices will cause a throw when opened for a broadcast address. - // We print and recover so the caller can loop through all bcast addrs. - uhd::transport::udp_simple::sptr udp_bcast_xport; - try { - udp_bcast_xport = uhd::transport::udp_simple::make_broadcast(addr_hint, port); - } catch(const std::exception &e) { - UHD_LOGGER_ERROR("E300") << boost::format("Cannot open UDP transport on %s for discovery%s") - % addr_hint % e.what() ; - return addrs; - } catch(...) { - UHD_LOGGER_ERROR("E300") << "E300 Network discovery unknown error"; - return addrs; - } - - // TODO: Do not abuse the I2C transport here ... - // we send a read request to i2c address 0x51, - // to read register 0 - i2c_transaction_t req; - req.type = i2c::READ | i2c::ONEBYTE; - req.addr = 0x51; // mboard's eeprom address, we don't really care - req.reg = 4; - - // send dummy request - try { - udp_bcast_xport->send(boost::asio::buffer(&req, sizeof(req))); - } catch (const std::exception &ex) { - UHD_LOGGER_ERROR("E300") << "E300 Network discovery error " << ex.what(); - return addrs; - } catch(...) { - UHD_LOGGER_ERROR("E300") << "E300 Network discovery unknown error"; - return addrs; - } - - // loop for replies until timeout - while (true) { - uint8_t buff[sizeof(i2c_transaction_t)] = {}; - const size_t nbytes = udp_bcast_xport->recv(boost::asio::buffer(buff), 0.050); - if (nbytes == 0) - break; //No more responses - - const i2c_transaction_t *reply = reinterpret_cast<const i2c_transaction_t*>(buff); - if (req.addr == reply->addr) - addrs.push_back(udp_bcast_xport->get_recv_addr()); - } - - return addrs; -} - -static bool is_loopback(const if_addrs_t &if_addrs) -{ - return if_addrs.inet == asio::ip::address_v4::loopback().to_string(); -} - -device_addrs_t e300_find(const device_addr_t &multi_dev_hint) -{ - // handle multi device discovery - device_addrs_t hints = separate_device_addr(multi_dev_hint); - - if (hints.size() > 1) { - device_addrs_t found_devices; - std::string err_msg; - BOOST_FOREACH(const device_addr_t &hint_i, hints) - { - device_addrs_t found_devices_i = e300_find(hint_i); - if(found_devices_i.size() != 1) - err_msg += str(boost::format( - "Could not resolve device hint \"%s\" to a single device.") - % hint_i.to_string()); - else - found_devices.push_back(found_devices_i[0]); - if (found_devices.empty()) - return device_addrs_t(); - - if (not err_msg.empty()) - throw uhd::value_error(err_msg); - } - return device_addrs_t(1, combine_device_addrs(found_devices)); - } - - // initialize the hint for a single device case - UHD_ASSERT_THROW(hints.size() <= 1); - hints.resize(1); // in case it was empty - device_addr_t hint = hints[0]; - device_addrs_t e300_addrs; - - // return an empty list of addresses when type is set to non-e300 - if (hint.has_key("type") and hint["type"] != "e3x0") - return e300_addrs; - - const bool loopback_only = - get_if_addrs().size() == 1 and is_loopback(get_if_addrs().at(0)); - - // if we don't have connectivity, we might as well skip the network part - if (not loopback_only) { - // if no address or node has been specified, send a broadcast - if ((not hint.has_key("addr")) and (not hint.has_key("node"))) { - BOOST_FOREACH(const if_addrs_t &if_addrs, get_if_addrs()) - { - // avoid the loopback device - if (is_loopback(if_addrs)) - continue; - - // create a new hint with this broadcast address - device_addr_t new_hint = hint; - new_hint["addr"] = if_addrs.bcast; - - // call discover with the new hint and append results - device_addrs_t new_e300_addrs = e300_find(new_hint); - e300_addrs.insert(e300_addrs.begin(), - new_e300_addrs.begin(), new_e300_addrs.end()); - - } - return e300_addrs; - } - - std::vector<std::string> ip_addrs = discover_ip_addrs( - hint["addr"], E300_SERVER_I2C_PORT); - - BOOST_FOREACH(const std::string &ip_addr, ip_addrs) - { - device_addr_t new_addr; - new_addr["type"] = "e3x0"; - new_addr["addr"] = ip_addr; - - // see if we can read the eeprom - try { - e300_eeprom_manager eeprom_manager( - i2c::make_simple_udp(new_addr["addr"], E300_SERVER_I2C_PORT)); - const mboard_eeprom_t eeprom = eeprom_manager.get_mb_eeprom(); - new_addr["name"] = eeprom["name"]; - new_addr["serial"] = eeprom["serial"]; - new_addr["product"] = eeprom_manager.get_mb_type_string(); - } catch (...) { - // set these values as empty string, so the device may still be found - // and the filters below can still operate on the discovered device - new_addr["name"] = ""; - new_addr["serial"] = ""; - } - // filter the discovered device below by matching optional keys - if ((not hint.has_key("name") or hint["name"] == new_addr["name"]) and - (not hint.has_key("serial") or hint["serial"] == new_addr["serial"])) - { - e300_addrs.push_back(new_addr); - } - } - } - - // finally search locally - // if device node is not provided, - // use the default one - if (not hint.has_key("node")) { - device_addr_t new_addr = hint; - new_addr["node"] = "/dev/axi_fpga"; - return e300_find(new_addr); - } - - // use the given node - if (fs::exists(hint["node"])) { - device_addr_t new_addr; - new_addr["type"] = "e3x0"; - new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string(); - - try { - e300_eeprom_manager eeprom_manager(i2c::make_i2cdev(E300_I2CDEV_DEVICE)); - const mboard_eeprom_t eeprom = eeprom_manager.get_mb_eeprom(); - new_addr["name"] = eeprom["name"]; - new_addr["serial"] = eeprom["serial"]; - new_addr["product"] = eeprom_manager.get_mb_type_string(); - } catch (...) { - // set these values as empty string, so the device may still be found - // and the filters below can still operate on the discovered device - new_addr["name"] = ""; - new_addr["serial"] = ""; - } - // filter the discovered device below by matching optional keys - if ((not hint.has_key("name") or hint["name"] == new_addr["name"]) and - (not hint.has_key("serial") or hint["serial"] == new_addr["serial"])) - { - e300_addrs.push_back(new_addr); - } - } - - return e300_addrs; -} - - -/*********************************************************************** - * Make - **********************************************************************/ -static device::sptr e300_make(const device_addr_t &device_addr) -{ - UHD_LOGGER_DEBUG("E300")<< "e300_make with args " << device_addr.to_pp_string() ; - if(device_addr.has_key("server")) - throw uhd::runtime_error( - str(boost::format("Please run the server executable \"%s\"") - % "usrp_e3x0_network_mode")); - else - return device::sptr(new e300_impl(device_addr)); -} - -// Common code used by e300_impl and e300_image_loader -void get_e3x0_fpga_images(const uhd::device_addr_t &device_addr, - std::string &fpga_image, - std::string &idle_image){ - const uint16_t pid = boost::lexical_cast<uint16_t>( - device_addr["product"]); - - //extract the FPGA path for the e300 - switch(e300_eeprom_manager::get_mb_type(pid)) { - case e300_eeprom_manager::USRP_E310_SG1_MB: - fpga_image = device_addr.cast<std::string>("fpga", - find_image_path(E310_SG1_FPGA_FILE_NAME)); - idle_image = find_image_path(E3XX_SG1_FPGA_IDLE_FILE_NAME); - break; - case e300_eeprom_manager::USRP_E310_SG3_MB: - fpga_image = device_addr.cast<std::string>("fpga", - find_image_path(E310_SG3_FPGA_FILE_NAME)); - idle_image = find_image_path(E3XX_SG3_FPGA_IDLE_FILE_NAME); - break; - case e300_eeprom_manager::USRP_E300_MB: - fpga_image = device_addr.cast<std::string>("fpga", - find_image_path(E300_FPGA_FILE_NAME)); - idle_image = find_image_path(E3XX_SG1_FPGA_IDLE_FILE_NAME); - break; - case e300_eeprom_manager::UNKNOWN: - default: - UHD_LOGGER_WARNING("E300") << "Unknown motherboard type, loading e300 image." - ; - fpga_image = device_addr.cast<std::string>("fpga", - find_image_path(E300_FPGA_FILE_NAME)); - idle_image = find_image_path(E3XX_SG1_FPGA_IDLE_FILE_NAME); - break; - } -} - -/*********************************************************************** - * Structors - **********************************************************************/ -e300_impl::e300_impl(const uhd::device_addr_t &device_addr) - : _device_addr(device_addr) - , _xport_path(device_addr.has_key("addr") ? ETH : AXI) - , _dma_chans_available(MAX_DMA_CHANNEL_PAIRS, ~size_t(0) /* all available at the beginning */) -{ - stream_options.rx_fc_request_freq = E300_RX_FC_REQUEST_FREQ; - - //////////////////////////////////////////////////////////////////// - // load the fpga image - //////////////////////////////////////////////////////////////////// - if (_xport_path == AXI) { - _do_not_reload = device_addr.has_key("no_reload_fpga"); - if (not _do_not_reload) { - std::string fpga_image; - - // need to re-read product ID code because of conversion into string in find function - e300_eeprom_manager eeprom_manager(i2c::make_i2cdev(E300_I2CDEV_DEVICE)); - const mboard_eeprom_t eeprom = eeprom_manager.get_mb_eeprom(); - device_addr_t device_addr_cp(device_addr.to_string()); - device_addr_cp["product"] = eeprom["product"]; - - get_e3x0_fpga_images(device_addr_cp, - fpga_image, - _idle_image); - common::load_fpga_image(fpga_image); - } - } - - //////////////////////////////////////////////////////////////////// - // setup fifo xports - //////////////////////////////////////////////////////////////////// - _ctrl_xport_params.recv_frame_size = e300::DEFAULT_CTRL_FRAME_SIZE; - _ctrl_xport_params.num_recv_frames = e300::DEFAULT_CTRL_NUM_FRAMES; - _ctrl_xport_params.send_frame_size = e300::DEFAULT_CTRL_FRAME_SIZE; - _ctrl_xport_params.num_send_frames = e300::DEFAULT_CTRL_NUM_FRAMES; - - _data_xport_params.recv_frame_size = device_addr.cast<size_t>("recv_frame_size", - e300::DEFAULT_RX_DATA_FRAME_SIZE); - _data_xport_params.num_recv_frames = device_addr.cast<size_t>("num_recv_frames", - e300::DEFAULT_RX_DATA_NUM_FRAMES); - _data_xport_params.send_frame_size = device_addr.cast<size_t>("send_frame_size", - e300::DEFAULT_TX_DATA_FRAME_SIZE); - _data_xport_params.num_send_frames = device_addr.cast<size_t>("num_send_frames", - e300::DEFAULT_TX_DATA_NUM_FRAMES); - - - // until we figure out why this goes wrong we'll keep this hack around for - // the ethernet case, in the AXI case we cannot go above one page - if (_xport_path == ETH) { - _data_xport_params.recv_frame_size = - std::min(e300::MAX_NET_RX_DATA_FRAME_SIZE, _data_xport_params.recv_frame_size); - _data_xport_params.send_frame_size = - std::min(e300::MAX_NET_TX_DATA_FRAME_SIZE, _data_xport_params.send_frame_size); - } else { - _data_xport_params.recv_frame_size = - std::min(e300::MAX_AXI_RX_DATA_FRAME_SIZE, _data_xport_params.recv_frame_size); - _data_xport_params.send_frame_size = - std::min(e300::MAX_AXI_TX_DATA_FRAME_SIZE, _data_xport_params.send_frame_size); - } - udp_zero_copy::buff_params dummy_buff_params_out; - - ad9361_ctrl::sptr codec_ctrl; - if (_xport_path == ETH) { - zero_copy_if::sptr codec_xport = - udp_zero_copy::make(device_addr["addr"], E300_SERVER_CODEC_PORT, _ctrl_xport_params, dummy_buff_params_out, device_addr); - codec_ctrl = e300_remote_codec_ctrl::make(codec_xport); - zero_copy_if::sptr gregs_xport = - udp_zero_copy::make(device_addr["addr"], E300_SERVER_GREGS_PORT, _ctrl_xport_params, dummy_buff_params_out, device_addr); - _global_regs = global_regs::make(gregs_xport); - - zero_copy_if::sptr i2c_xport; - i2c_xport = udp_zero_copy::make(device_addr["addr"], E300_SERVER_I2C_PORT, _ctrl_xport_params, dummy_buff_params_out, device_addr); - _eeprom_manager = boost::make_shared<e300_eeprom_manager>(i2c::make_zc(i2c_xport)); - - uhd::transport::zero_copy_xport_params sensor_xport_params; - sensor_xport_params.recv_frame_size = 128; - sensor_xport_params.num_recv_frames = 10; - sensor_xport_params.send_frame_size = 128; - sensor_xport_params.num_send_frames = 10; - - zero_copy_if::sptr sensors_xport; - sensors_xport = udp_zero_copy::make(device_addr["addr"], E300_SERVER_SENSOR_PORT, sensor_xport_params, dummy_buff_params_out, device_addr); - _sensor_manager = e300_sensor_manager::make_proxy(sensors_xport); - - } else { - e300_fifo_config_t fifo_cfg; - try { - fifo_cfg = e300_read_sysfs(); - } catch (...) { - throw uhd::runtime_error("Failed to get driver parameters from sysfs."); - } - _fifo_iface = e300_fifo_interface::make(fifo_cfg); - _global_regs = global_regs::make(_fifo_iface->get_global_regs_base()); - - ad9361_params::sptr client_settings = boost::make_shared<e300_ad9361_client_t>(); - codec_ctrl = ad9361_ctrl::make_spi(client_settings, spi::make(E300_SPIDEV_DEVICE), 1); - // This is horrible ... why do I have to sleep here? - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); - _eeprom_manager = boost::make_shared<e300_eeprom_manager>(i2c::make_i2cdev(E300_I2CDEV_DEVICE)); - _sensor_manager = e300_sensor_manager::make_local(_global_regs); - } - -#ifdef E300_GPSD - UHD_LOGGER_INFO("E300") << "Detecting internal GPS "; - try { - if (_xport_path == AXI) - _gps = gpsd_iface::make("localhost", 2947); - else - _gps = gpsd_iface::make(device_addr["addr"], 2947); - } catch (std::exception &e) { - UHD_LOGGER_ERROR("E300") << "An error occured making GPSDd interface: " << e.what(); - } - - if (_gps) { - for (size_t i = 0; i < _GPS_TIMEOUT; i++) - { - boost::this_thread::sleep(boost::posix_time::seconds(1)); - if (!_gps->gps_detected()) - std::cout << "." << std::flush; - else { - std::cout << ".... " << std::flush; - break; - } - } - UHD_LOGGER_INFO("E300") << "GPSDO " << (_gps->gps_detected() ? "found" : "not found"); - } -#endif - - // Verify we can talk to the e300 core control registers ... - UHD_LOGGER_INFO("E300") << "Initializing core control (global registers)..." << std::endl; - this->_register_loopback_self_test( - _global_regs, - global_regs::SR_CORE_TEST, - global_regs::RB32_CORE_TEST - ); - - // Verify fpga compatibility version matches at least for the major - if (_get_version(FPGA_MAJOR) != fpga::COMPAT_MAJOR) { - throw uhd::runtime_error(str(boost::format( - "Expected FPGA compatibility number %lu.x, but got %lu.%lu:\n" - "The FPGA build is not compatible with the host code build.\n" - "%s" - ) % fpga::COMPAT_MAJOR - % _get_version(FPGA_MAJOR) % _get_version(FPGA_MINOR) - % print_utility_error("uhd_images_downloader.py"))); - } - - //////////////////////////////////////////////////////////////////// - // Initialize the properties tree - //////////////////////////////////////////////////////////////////// - _tree->create<std::string>("/name").set("E-Series Device"); - const fs_path mb_path = "/mboards/0"; - _tree->create<std::string>(mb_path / "name") - .set(_eeprom_manager->get_mb_type_string()); - - _tree->create<std::string>(mb_path / "codename").set("Troll"); - - _tree->create<std::string>(mb_path / "fpga_version").set( - str(boost::format("%u.%u") - % _get_version(FPGA_MAJOR) - % _get_version(FPGA_MINOR))); - - _tree->create<std::string>(mb_path / "fpga_version_hash").set( - _get_version_hash()); - - // Clock reference source - _tree->create<std::string>(mb_path / "clock_source" / "value") - .add_coerced_subscriber(boost::bind(&e300_impl::_update_clock_source, this, _1)) - .set(e300::DEFAULT_CLOCK_SRC); - static const std::vector<std::string> clock_sources = - boost::assign::list_of("internal"); //external,gpsdo not supported - _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_sources); - - //////////////////////////////////////////////////////////////////// - // and do the misc mboard sensors - //////////////////////////////////////////////////////////////////// - _tree->create<int>(mb_path / "sensors"); - BOOST_FOREACH(const std::string &name, _sensor_manager->get_sensors()) - { - _tree->create<sensor_value_t>(mb_path / "sensors" / name) - .set_publisher(boost::bind(&e300_sensor_manager::get_sensor, _sensor_manager, name)); - } -#ifdef E300_GPSD - if (_gps) { - BOOST_FOREACH(const std::string &name, _gps->get_sensors()) - { - _tree->create<sensor_value_t>(mb_path / "sensors" / name) - .set_publisher(boost::bind(&gpsd_iface::get_sensor, _gps, name)); - } - } -#endif - - //////////////////////////////////////////////////////////////////// - // setup the mboard eeprom - //////////////////////////////////////////////////////////////////// - _tree->create<mboard_eeprom_t>(mb_path / "eeprom") - .set(_eeprom_manager->get_mb_eeprom()) // set first... - .add_coerced_subscriber(boost::bind( - &e300_eeprom_manager::write_mb_eeprom, - _eeprom_manager, _1)); - - //////////////////////////////////////////////////////////////////// - // dboard eeproms but not really - //////////////////////////////////////////////////////////////////// - dboard_eeprom_t db_eeprom; - _tree->create<dboard_eeprom_t>(mb_path / "dboards" / "A" / "rx_eeprom") - .set(_eeprom_manager->get_db_eeprom()) - .add_coerced_subscriber(boost::bind( - &e300_eeprom_manager::write_db_eeprom, - _eeprom_manager, _1)); - - _tree->create<dboard_eeprom_t>(mb_path / "dboards" / "A" / "tx_eeprom") - .set(_eeprom_manager->get_db_eeprom()) - .add_coerced_subscriber(boost::bind( - &e300_eeprom_manager::write_db_eeprom, - _eeprom_manager, _1)); - - _tree->create<dboard_eeprom_t>(mb_path / "dboards" / "A" / "gdb_eeprom").set(db_eeprom); - - //////////////////////////////////////////////////////////////////// - // Access to global regs - //////////////////////////////////////////////////////////////////// - _tree->create<uint32_t>(mb_path / "global_regs" / "misc") - .add_coerced_subscriber(boost::bind(&global_regs::poke32, _global_regs, global_regs::SR_CORE_MISC, _1)) - ; - _tree->create<uint32_t>(mb_path / "global_regs" / "pll") - .set_publisher(boost::bind(&global_regs::peek32, _global_regs, global_regs::RB32_CORE_PLL)) - ; - - //////////////////////////////////////////////////////////////////// - // clocking - //////////////////////////////////////////////////////////////////// - _tree->create<double>(mb_path / "tick_rate") - .add_coerced_subscriber(boost::bind(&device3_impl::update_tx_streamers, this, _1)) - .add_coerced_subscriber(boost::bind(&device3_impl::update_rx_streamers, this, _1)) - ; - - //default some chains on -- needed for setup purposes - UHD_LOGGER_DEBUG("E300") << "Initializing AD9361 using hard SPI core..." << std::flush; - codec_ctrl->set_active_chains(true, false, true, false); - codec_ctrl->set_clock_rate(50e6); - UHD_LOGGER_DEBUG("E300") << "OK" << std::endl; - - //////////////////////////////////////////////////////////////////// - // Set up RFNoC blocks - //////////////////////////////////////////////////////////////////// - const size_t n_rfnoc_blocks = _global_regs->peek32(global_regs::RB32_CORE_NUM_CE); - enumerate_rfnoc_blocks( - 0, /* mboard index */ - n_rfnoc_blocks, - E300_XB_DST_AXI + 1, /* base port, rfnoc blocks come after the AXI connect */ - uhd::sid_t(E300_DEVICE_HERE, 0, E300_DEVICE_THERE, 0), - device_addr_t() - ); - - // If we have a radio, we must configure its codec control: - std::vector<rfnoc::block_id_t> radio_ids = find_blocks<rfnoc::e3xx_radio_ctrl_impl>("Radio"); - if (radio_ids.size() > 0) { - UHD_LOGGER_DEBUG("E300") << "Initializing Radio Block..." << std::endl; - get_block_ctrl<rfnoc::e3xx_radio_ctrl_impl>(radio_ids[0])->setup_radio(codec_ctrl); - if (radio_ids.size() != 1) { - UHD_LOGGER_WARNING("E300") << "Too many Radio Blocks found. Using only " << radio_ids[0] << std::endl; - } - } else { - UHD_LOGGER_DEBUG("E300") << "No Radio Block found. Assuming radio-less operation." << std::endl; - } - - //////////////////////////////////////////////////////////////////// - // do some post-init tasks - //////////////////////////////////////////////////////////////////// - // init the clock rate to something reasonable - _tree->access<double>(mb_path / "tick_rate") - .set(device_addr.cast<double>("master_clock_rate", ad936x_manager::DEFAULT_TICK_RATE)); - - // subdev spec contains full width of selections - subdev_spec_t rx_spec, tx_spec; - BOOST_FOREACH(const std::string &fe, _tree->list(mb_path / "dboards" / "A" / "rx_frontends")) - { - rx_spec.push_back(subdev_spec_pair_t("A", fe)); - } - BOOST_FOREACH(const std::string &fe, _tree->list(mb_path / "dboards" / "A" / "tx_frontends")) - { - tx_spec.push_back(subdev_spec_pair_t("A", fe)); - } - _tree->create<subdev_spec_t>(mb_path / "rx_subdev_spec").set(rx_spec); - _tree->create<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_spec); - UHD_LOGGER_DEBUG("E300") << "end of e300_impl()" << std::endl; -} - -e300_impl::~e300_impl(void) -{ - // Force RFNoC destructors to fire before loading the idle image - _rfnoc_block_ctrl.clear(); - if (_xport_path == AXI and not _do_not_reload) - common::load_fpga_image(_idle_image); -} - -void e300_impl::_register_loopback_self_test(wb_iface::sptr iface, uint32_t w_addr, uint32_t r_addr) -{ - bool test_fail = false; - UHD_LOGGER_INFO("E300") << "Performing register loopback test... "; - size_t hash = size_t(time(NULL)); - for (size_t i = 0; i < 100; i++) - { - boost::hash_combine(hash, i); - iface->poke32(w_addr, uint32_t(hash)); - test_fail = iface->peek32(r_addr) != uint32_t(hash); - if (test_fail) break; //exit loop on any failure - } - UHD_LOGGER_INFO("E300") << "Register loopback test " << ((test_fail)? " failed" : "passed"); -} - -uint32_t e300_impl::_get_version(compat_t which) -{ - const uint16_t compat_num - = _global_regs->peek32(global_regs::RB32_CORE_COMPAT); - - switch(which) { - case FPGA_MINOR: - return compat_num & 0xff; - case FPGA_MAJOR: - return (compat_num & 0xff00) >> 8; - default: - throw uhd::value_error("Requested unknown version."); - }; -} - -std::string e300_impl::_get_version_hash(void) -{ - const uint32_t git_hash - = _global_regs->peek32(global_regs::RB32_CORE_GITHASH); - return str(boost::format("%7x%s") - % (git_hash & 0x0FFFFFFF) - % ((git_hash & 0xF0000000) ? "-dirty" : "")); -} - - -void e300_impl::_setup_dest_mapping( - const uhd::sid_t &sid, - const size_t which_stream) -{ - UHD_LOGGER_DEBUG("E300") << boost::format("[E300] Setting up dest map for host ep %lu to be stream %d") - % sid.get_src_endpoint() % which_stream << std::endl; - _global_regs->poke32(DST_ADDR(sid.get_src_endpoint()), which_stream); -} - -size_t e300_impl::_get_axi_dma_channel_pair() -{ - if (_dma_chans_available.none()) { - throw uhd::runtime_error("No more free DMA channels available."); - } - - size_t first_free_pair = _dma_chans_available.find_first(); - _dma_chans_available.reset(first_free_pair); - return first_free_pair; -} - -uint16_t e300_impl::_get_udp_port( - uint8_t destination, - uint8_t prefix) -{ - if (destination == E300_XB_DST_RADIO) { - if (prefix == E300_RADIO_DEST_PREFIX_CTRL) - return boost::lexical_cast<uint16_t>(E300_SERVER_CTRL_PORT0); - else if (prefix == E300_RADIO_DEST_PREFIX_TX) - return boost::lexical_cast<uint16_t>(E300_SERVER_TX_PORT0); - else if (prefix == E300_RADIO_DEST_PREFIX_RX) - return boost::lexical_cast<uint16_t>(E300_SERVER_RX_PORT0); - } else if (destination == E300_XB_DST_R1) { - if (prefix == E300_RADIO_DEST_PREFIX_CTRL) - return boost::lexical_cast<uint16_t>(E300_SERVER_CTRL_PORT1); - else if (prefix == E300_RADIO_DEST_PREFIX_TX) - return boost::lexical_cast<uint16_t>(E300_SERVER_TX_PORT1); - else if (prefix == E300_RADIO_DEST_PREFIX_RX) - return boost::lexical_cast<uint16_t>(E300_SERVER_RX_PORT1); - } - throw uhd::value_error(str(boost::format("No UDP port defined for combination: %u %u") % destination % prefix)); -} - -uhd::sid_t e300_impl::_allocate_sid( - const uhd::sid_t &address) -{ - uhd::sid_t sid = address; - sid.set_src_addr(E300_DEVICE_HERE); - sid.set_src_endpoint(_sid_framer); - - // TODO: We don't have to do this everytime ... - // Program the E300 to recognize it's own local address. - _global_regs->poke32(global_regs::SR_CORE_XB_LOCAL, address.get_dst_addr()); - - // Program CAM entry for outgoing packets matching a E300 resource - // (e.g. Radio). - // This type of packet matches the XB_LOCAL address and is looked up in - // the upper half of the CAM - _global_regs->poke32(XB_ADDR(256 + address.get_dst_endpoint()), address.get_dst_xbarport()); - - // TODO: We don't have to do this everytime ... - // Program CAM entry for returning packets to us - // (for example host via zynq_fifo) - // This type of packet does not match the XB_LOCAL address and is - // looked up in the lower half of the CAM - _global_regs->poke32(XB_ADDR(E300_DEVICE_HERE), E300_XB_DST_AXI); - - // increment for next setup - _sid_framer++; - - return sid; -} - -uhd::both_xports_t e300_impl::make_transport( - const uhd::sid_t &address, - const xport_type_t type, - const uhd::device_addr_t &) -{ - uhd::both_xports_t xports; - xports.endianness = ENDIANNESS_LITTLE; - - const uhd::transport::zero_copy_xport_params params = - (type == CTRL) ? _ctrl_xport_params : _data_xport_params; - - xports.send_sid = _allocate_sid(address); - xports.recv_sid = xports.send_sid.reversed(); - xports.recv_buff_size = params.recv_frame_size * params.num_recv_frames; - xports.send_buff_size = params.send_frame_size * params.num_send_frames; - - if (_xport_path != AXI) { - throw uhd::runtime_error("[E300] Currently only AXI transport supported with RFNOC"); - } - - const size_t chan_pair = _get_axi_dma_channel_pair(); - xports.send = _fifo_iface->make_send_xport(chan_pair, params); - xports.recv = _fifo_iface->make_recv_xport(chan_pair, params); - _setup_dest_mapping(xports.send_sid, chan_pair); - - return xports; -} - -void e300_impl::_update_clock_source(const std::string &source) -{ - if (source != "internal") { - throw uhd::value_error(boost::str( - boost::format("Clock source option not supported: %s. The only value supported is \"internal\". " \ - "To discipline the internal oscillator, set the appropriate time source.") % source - )); - } -} - -}}} // namespace - -UHD_STATIC_BLOCK(register_e300_device) -{ - device::register_device(&uhd::usrp::e300::e300_find, &uhd::usrp::e300::e300_make, uhd::device::USRP); -} diff --git a/host/lib/usrp/e300/e300_impl.hpp b/host/lib/usrp/e300/e300_impl.hpp deleted file mode 100644 index 2e919cf9b..000000000 --- a/host/lib/usrp/e300/e300_impl.hpp +++ /dev/null @@ -1,195 +0,0 @@ -// -// Copyright 2013-2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_IMPL_HPP -#define INCLUDED_E300_IMPL_HPP - -#include "../device3/device3_impl.hpp" -#include <uhd/property_tree.hpp> -#include <uhd/usrp/mboard_eeprom.hpp> -#include <uhd/usrp/dboard_eeprom.hpp> -#include <uhd/usrp/subdev_spec.hpp> -#include <uhd/types/serial.hpp> -#include <uhd/types/sensors.hpp> - -#include <boost/weak_ptr.hpp> -#include <boost/thread/mutex.hpp> -#include <boost/dynamic_bitset.hpp> -#include <string> -#include "e300_fifo_config.hpp" - -#include "e300_global_regs.hpp" -#include "e300_i2c.hpp" -#include "e300_eeprom_manager.hpp" -#include "e300_sensor_manager.hpp" - -/* if we don't compile with gpsd support, don't bother */ -#ifdef E300_GPSD -#include "gpsd_iface.hpp" -#endif - -#include <atomic> - -namespace uhd { namespace usrp { namespace e300 { - -static const std::string E300_FPGA_FILE_NAME = "usrp_e300_fpga.bit"; -static const std::string E310_SG1_FPGA_FILE_NAME = "usrp_e310_fpga.bit"; -static const std::string E310_SG3_FPGA_FILE_NAME = "usrp_e310_fpga_sg3.bit"; - -static const std::string E3XX_SG1_FPGA_IDLE_FILE_NAME = "usrp_e3xx_fpga_idle.bit"; -static const std::string E3XX_SG3_FPGA_IDLE_FILE_NAME = "usrp_e3xx_fpga_idle_sg3.bit"; - -static const std::string E300_TEMP_SYSFS = "iio:device0"; -static const std::string E300_SPIDEV_DEVICE = "/dev/spidev0.1"; -static const std::string E300_I2CDEV_DEVICE = "/dev/i2c-0"; - -static std::string E300_SERVER_RX_PORT0 = "21756"; -static std::string E300_SERVER_TX_PORT0 = "21757"; -static std::string E300_SERVER_CTRL_PORT0 = "21758"; - -static std::string E300_SERVER_RX_PORT1 = "21856"; -static std::string E300_SERVER_TX_PORT1 = "21857"; -static std::string E300_SERVER_CTRL_PORT1 = "21858"; - - -static std::string E300_SERVER_CODEC_PORT = "21759"; -static std::string E300_SERVER_GREGS_PORT = "21760"; -static std::string E300_SERVER_I2C_PORT = "21761"; -static std::string E300_SERVER_SENSOR_PORT = "21762"; - -static const double E300_RX_SW_BUFF_FULLNESS = 0.9; //Buffer should be half full -static const size_t E300_RX_FC_REQUEST_FREQ = 5; // per flow ctrl window -static const size_t E300_TX_FC_RESPONSE_FREQ = 8; // per flow ctrl window - -// crossbar settings -static const uint8_t E300_RADIO_DEST_PREFIX_TX = 0; -static const uint8_t E300_RADIO_DEST_PREFIX_CTRL = 1; -static const uint8_t E300_RADIO_DEST_PREFIX_RX = 2; - -static const uint8_t E300_XB_DST_AXI = 0; -static const uint8_t E300_XB_DST_RADIO = 1; -static const uint8_t E300_XB_DST_R1 = 2; -// RFNoC blocks are connected to the first port -// after the last radio (there might be less than 2 -// radios). - -static const uint8_t E300_DEVICE_THERE = 2; -static const uint8_t E300_DEVICE_HERE = 0; - -static const size_t E300_R0_CTRL_STREAM = (0 << 2) | E300_RADIO_DEST_PREFIX_CTRL; -static const size_t E300_R0_TX_DATA_STREAM = (0 << 2) | E300_RADIO_DEST_PREFIX_TX; -static const size_t E300_R0_RX_DATA_STREAM = (0 << 2) | E300_RADIO_DEST_PREFIX_RX; - -static const size_t E300_R1_CTRL_STREAM = (1 << 2) | E300_RADIO_DEST_PREFIX_CTRL; -static const size_t E300_R1_TX_DATA_STREAM = (1 << 2) | E300_RADIO_DEST_PREFIX_TX; -static const size_t E300_R1_RX_DATA_STREAM = (1 << 2) | E300_RADIO_DEST_PREFIX_RX; - -uhd::device_addrs_t e300_find(const uhd::device_addr_t &multi_dev_hint); -void get_e3x0_fpga_images(const uhd::device_addr_t &device_args, - std::string &fpga_image, - std::string &idle_image); - -/*! - * USRP-E300 implementation guts: - * The implementation details are encapsulated here. - * Handles properties on the mboard, dboard, dsps... - */ -class e300_impl : public uhd::usrp::device3_impl -{ -public: - /************************************************************************ - * Structors - ***********************************************************************/ - e300_impl(const uhd::device_addr_t &); - virtual ~e300_impl(void); - -private: // types - enum compat_t {FPGA_MAJOR, FPGA_MINOR}; - -protected: // methods - /************************************************************************ - * Legacy device3 stuff - ***********************************************************************/ - void subdev_to_blockid( - const uhd::usrp::subdev_spec_pair_t &spec, const size_t mb_i, - rfnoc::block_id_t &block_id, uhd::device_addr_t &block_args - ); - uhd::usrp::subdev_spec_pair_t blockid_to_subdev( - const rfnoc::block_id_t &blockid, const device_addr_t &block_args - ); - - /************************************************************************ - * Transport related - ***********************************************************************/ - uhd::device_addr_t get_rx_hints(size_t); - -private: // methods - /************************************************************************ - * Initialization - ***********************************************************************/ - void _register_loopback_self_test(wb_iface::sptr iface, uint32_t w_addr, uint32_t r_addr); - - uint32_t _get_version(compat_t which); - std::string _get_version_hash(void); - - /************************************************************************ - * Transport related - ***********************************************************************/ - uhd::sid_t _allocate_sid(const uhd::sid_t &address); - - void _setup_dest_mapping( - const uhd::sid_t &sid, - const size_t which_stream); - - /*! Return the first free AXI channel pair. - * - * \throws uhd::runtime_error if no free channel pairs are available. - */ - size_t _get_axi_dma_channel_pair(); - - // For network mode - uint16_t _get_udp_port( - uint8_t destination, - uint8_t prefix); - - uhd::both_xports_t make_transport( - const uhd::sid_t &address, - const xport_type_t type, - const uhd::device_addr_t &args - ); - - uhd::endianness_t get_transport_endianness(size_t) { - return uhd::ENDIANNESS_LITTLE; - }; - - /************************************************************************ - * Helpers - ***********************************************************************/ - void _update_clock_source(const std::string &); - -private: // members - const uhd::device_addr_t _device_addr; - xport_t _xport_path; - e300_fifo_interface::sptr _fifo_iface; - std::atomic<size_t> _sid_framer; - boost::dynamic_bitset<> _dma_chans_available; - global_regs::sptr _global_regs; - e300_sensor_manager::sptr _sensor_manager; - e300_eeprom_manager::sptr _eeprom_manager; - uhd::transport::zero_copy_xport_params _data_xport_params; - uhd::transport::zero_copy_xport_params _ctrl_xport_params; - std::string _idle_image; - bool _do_not_reload; -#ifdef E300_GPSD - gpsd_iface::sptr _gps; - static const size_t _GPS_TIMEOUT = 5; -#endif -}; - -}}} // namespace uhd::usrp::e300 - -#endif /* INCLUDED_E300_IMPL_HPP */ diff --git a/host/lib/usrp/e300/e300_io_impl.cpp b/host/lib/usrp/e300/e300_io_impl.cpp deleted file mode 100644 index 4460d5616..000000000 --- a/host/lib/usrp/e300/e300_io_impl.cpp +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright 2013-2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "e300_regs.hpp" -#include "e300_impl.hpp" -#include "e300_fpga_defs.hpp" -#include "e300_defaults.hpp" -#include "../../transport/super_recv_packet_handler.hpp" -#include "../../transport/super_send_packet_handler.hpp" -#include <uhd/utils/tasks.hpp> -#include <boost/bind.hpp> -#include <boost/format.hpp> - -using namespace uhd; -using namespace uhd::usrp; -using namespace uhd::transport; - -namespace uhd { namespace usrp { namespace e300 { - -uhd::device_addr_t e300_impl::get_rx_hints(size_t) -{ - return uhd::device_addr_t(str(boost::format("max_recv_window=%d") % DEFAULT_RX_DATA_NUM_FRAMES)); -} - -}}} // namespace diff --git a/host/lib/usrp/e300/e300_network.cpp b/host/lib/usrp/e300/e300_network.cpp deleted file mode 100644 index d9a104dda..000000000 --- a/host/lib/usrp/e300/e300_network.cpp +++ /dev/null @@ -1,655 +0,0 @@ -// -// Copyright 2013-2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "e300_network.hpp" - -#ifdef E300_NATIVE - -#include "e300_impl.hpp" - -#include "e300_sensor_manager.hpp" -#include "e300_fifo_config.hpp" -#include "e300_spi.hpp" -#include "e300_i2c.hpp" -#include "e300_defaults.hpp" -#include "e300_common.hpp" -#include "e300_remote_codec_ctrl.hpp" - -#include <uhd/utils/log.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/paths.hpp> - -#include <uhdlib/usrp/common/ad9361_ctrl.hpp> - -#include <boost/asio.hpp> -#include <boost/filesystem.hpp> -#include <boost/make_shared.hpp> - -#include <fstream> -#include <chrono> -#include <thread> - -using namespace uhd; -using namespace uhd::transport; -namespace asio = boost::asio; -namespace fs = boost::filesystem; - -namespace uhd { namespace usrp { namespace e300 { - -static const size_t E300_NETWORK_DEBUG = false; - -static inline bool wait_for_recv_ready(int sock_fd, const size_t timeout_ms) -{ - //setup timeval for timeout - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = timeout_ms*1000; - - //setup rset for timeout - fd_set rset; - FD_ZERO(&rset); - FD_SET(sock_fd, &rset); - - //call select with timeout on receive socket - return ::select(sock_fd+1, &rset, NULL, NULL, &tv) > 0; -} - -static boost::mutex endpoint_mutex; - -/*********************************************************************** - * Receive tunnel - forwards recv interface to send socket - **********************************************************************/ -static void e300_recv_tunnel( - const std::string &name, - uhd::transport::zero_copy_if::sptr recver, - boost::shared_ptr<asio::ip::udp::socket> sender, - asio::ip::udp::endpoint *endpoint, - bool *running -) -{ - asio::ip::udp::endpoint _tx_endpoint; - try - { - while (*running) - { - //step 1 - get the buffer - managed_recv_buffer::sptr buff = recver->get_recv_buff(); - if (not buff) continue; - if (E300_NETWORK_DEBUG) UHD_LOGGER_INFO("E300") << name << " got " << buff->size(); - - //step 1.5 -- update endpoint - { - boost::mutex::scoped_lock l(endpoint_mutex); - _tx_endpoint = *endpoint; - } - - //step 2 - send to the socket - sender->send_to(asio::buffer(buff->cast<const void *>(), buff->size()), _tx_endpoint); - } - } - catch(const std::exception &ex) - { - UHD_LOGGER_ERROR("E300") << "e300_recv_tunnel exit " << name << " " << ex.what(); - } - catch(...) - { - UHD_LOGGER_ERROR("E300") << "e300_recv_tunnel exit " << name ; - } - UHD_LOGGER_INFO("E300") << "e300_recv_tunnel exit " << name; - *running = false; -} - -/*********************************************************************** - * Send tunnel - forwards recv socket to send interface - **********************************************************************/ -static void e300_send_tunnel( - const std::string &name, - boost::shared_ptr<asio::ip::udp::socket> recver, - uhd::transport::zero_copy_if::sptr sender, - asio::ip::udp::endpoint *endpoint, - bool *running -) -{ - asio::ip::udp::endpoint _rx_endpoint; - try - { - while (*running) - { - //step 1 - get the buffer - managed_send_buffer::sptr buff = sender->get_send_buff(); - if (not buff) continue; - - //step 2 - recv from socket - while (not wait_for_recv_ready(recver->native_handle(), 100) and *running){} - if (not *running) break; - const size_t num_bytes = recver->receive_from(asio::buffer(buff->cast<void *>(), buff->size()), _rx_endpoint); - if (E300_NETWORK_DEBUG) UHD_LOGGER_INFO("E300") << name << " got " << num_bytes; - - //step 2.5 -- update endpoint - { - boost::mutex::scoped_lock l(endpoint_mutex); - *endpoint = _rx_endpoint; - } - - //step 3 - commit the buffer - buff->commit(num_bytes); - } - } - catch(const std::exception &ex) - { - UHD_LOGGER_ERROR("E300") << "e300_send_tunnel exit " << name << " " << ex.what() ; - } - catch(...) - { - UHD_LOGGER_ERROR("E300") << "e300_send_tunnel exit " << name ; - } - UHD_LOGGER_INFO("E300") << "e300_send_tunnel exit " << name; - *running = false; -} - -static void e300_codec_ctrl_tunnel( - const std::string &name, - boost::shared_ptr<asio::ip::udp::socket> socket, - ad9361_ctrl::sptr _codec_ctrl, - asio::ip::udp::endpoint *endpoint, - bool *running -) -{ - asio::ip::udp::endpoint _endpoint; - try - { - while (*running) - { - uint8_t in_buff[64] = {}; - uint8_t out_buff[64] = {}; - - const size_t num_bytes = socket->receive_from(asio::buffer(in_buff), *endpoint); - - typedef e300_remote_codec_ctrl::transaction_t codec_xact_t; - - if (num_bytes < sizeof(codec_xact_t)) { - std::cout << "Received short packet of " << num_bytes << std::endl; - continue; - } - - codec_xact_t *in = reinterpret_cast<codec_xact_t*>(in_buff); - codec_xact_t *out = reinterpret_cast<codec_xact_t*>(out_buff); - std::memcpy(out, in, sizeof(codec_xact_t)); - - std::string which_str; - switch (uhd::ntohx<uint32_t>(in->which)) { - case codec_xact_t::CHAIN_TX1: - which_str = "TX1"; break; - case codec_xact_t::CHAIN_TX2: - which_str = "TX2"; break; - case codec_xact_t::CHAIN_RX1: - which_str = "RX1"; break; - case codec_xact_t::CHAIN_RX2: - which_str = "RX2"; break; - default: - which_str = ""; break; - } - - switch (uhd::ntohx<uint32_t>(in->action)) { - case codec_xact_t::ACTION_SET_GAIN: - out->gain = _codec_ctrl->set_gain(which_str, in->gain); - break; - case codec_xact_t::ACTION_SET_CLOCK_RATE: - out->rate = _codec_ctrl->set_clock_rate(in->rate); - break; - case codec_xact_t::ACTION_SET_ACTIVE_CHANS: - _codec_ctrl->set_active_chains( - uhd::ntohx<uint32_t>(in->bits) & (1<<0), - uhd::ntohx<uint32_t>(in->bits) & (1<<1), - uhd::ntohx<uint32_t>(in->bits) & (1<<2), - uhd::ntohx<uint32_t>(in->bits) & (1<<3)); - break; - case codec_xact_t::ACTION_TUNE: - out->freq = _codec_ctrl->tune(which_str, in->freq); - break; - case codec_xact_t::ACTION_GET_FREQ: - out->freq = _codec_ctrl->get_freq(which_str); - break; - case codec_xact_t::ACTION_SET_LOOPBACK: - _codec_ctrl->data_port_loopback( - uhd::ntohx<uint32_t>(in->bits) & 1); - break; - case codec_xact_t::ACTION_GET_RSSI: - out->rssi = _codec_ctrl->get_rssi(which_str).to_real(); - break; - case codec_xact_t::ACTION_GET_TEMPERATURE: - out->temp = _codec_ctrl->get_temperature().to_real(); - break; - case codec_xact_t::ACTION_SET_DC_OFFSET_AUTO: - _codec_ctrl->set_dc_offset_auto(which_str, in->use_dc_correction == 1); - break; - case codec_xact_t::ACTION_SET_IQ_BALANCE_AUTO: - _codec_ctrl->set_iq_balance_auto(which_str, in->use_iq_correction == 1); - case codec_xact_t::ACTION_SET_AGC: - _codec_ctrl->set_agc(which_str, in->use_agc == 1); - break; - case codec_xact_t::ACTION_SET_AGC_MODE: - if(in->agc_mode == 0) { - _codec_ctrl->set_agc_mode(which_str, "slow"); - } else if (in->agc_mode == 1) { - _codec_ctrl->set_agc_mode(which_str, "fast"); - } - break; - case codec_xact_t::ACTION_SET_BW: - out->bw = _codec_ctrl->set_bw_filter(which_str, in->bw); - break; - default: - UHD_LOGGER_INFO("E300") << "Got unknown request?!"; - //Zero out actions to fail this request on client - out->action = uhd::htonx<uint32_t>(0); - } - - socket->send_to(asio::buffer(out_buff, 64), *endpoint); - } - } - catch(const std::exception &ex) - { - UHD_LOGGER_ERROR("E300") << "e300_ctrl_tunnel exit " << name << " " << ex.what() ; - } - catch(...) - { - UHD_LOGGER_ERROR("E300") << "e300_ctrl_tunnel exit " << name ; - } - UHD_LOGGER_INFO("E300") << "e300_ctrl_tunnel exit " << name; - *running = false; -} - -static void e300_global_regs_tunnel( - const std::string &name, - boost::shared_ptr<asio::ip::udp::socket> socket, - global_regs::sptr regs, - asio::ip::udp::endpoint *endpoint, - bool *running -) -{ - UHD_ASSERT_THROW(regs); - asio::ip::udp::endpoint _endpoint; - try - { - while (*running) - { - uint8_t in_buff[16] = {}; - - const size_t num_bytes = socket->receive_from(asio::buffer(in_buff), *endpoint); - - if (num_bytes < 16) { - std::cout << "Received short packet: " << num_bytes << std::endl; - continue; - } - - global_regs_transaction_t *in = - reinterpret_cast<global_regs_transaction_t *>(in_buff); - - if(uhd::ntohx<uint32_t>(in->is_poke)) { - regs->poke32(uhd::ntohx<uint32_t>(in->addr), uhd::ntohx<uint32_t>(in->data)); - } - else { - in->data = uhd::htonx<uint32_t>(regs->peek32(uhd::ntohx<uint32_t>(in->addr))); - socket->send_to(asio::buffer(in_buff, 16), *endpoint); - } - } - } - catch(const std::exception &ex) - { - UHD_LOGGER_ERROR("E300") << "e300_gregs_tunnel exit " << name << " " << ex.what() ; - } - catch(...) - { - UHD_LOGGER_ERROR("E300") << "e300_gregs_tunnel exit " << name ; - } - UHD_LOGGER_INFO("E300") << "e300_gregs_tunnel exit " << name; - *running = false; -} - -static void e300_sensor_tunnel( - const std::string &name, - boost::shared_ptr<asio::ip::udp::socket> socket, - e300_sensor_manager::sptr sensor_manager, - asio::ip::udp::endpoint *endpoint, - bool *running -) -{ - asio::ip::udp::endpoint _endpoint; - try - { - while (*running) - { - uint8_t in_buff[128] = {}; - - const size_t num_bytes = socket->receive_from(asio::buffer(in_buff), *endpoint); - - if (num_bytes < sizeof(sensor_transaction_t)) { - std::cout << "Received short packet: " << num_bytes << std::endl; - continue; - } - - uhd::usrp::e300::sensor_transaction_t *in = - reinterpret_cast<uhd::usrp::e300::sensor_transaction_t *>(in_buff); - - if (uhd::ntohx(in->which) == ZYNQ_TEMP) { - sensor_value_t temp = sensor_manager->get_mb_temp(); - // TODO: This is ugly ... use proper serialization - in->value = uhd::htonx<uint32_t>( - e300_sensor_manager::pack_float_in_uint32_t(temp.to_real())); - } else if (uhd::ntohx(in->which) == REF_LOCK) { - in->value = uhd::htonx<uint32_t>( - sensor_manager->get_ref_lock().to_bool() ? 1 : 0); - } else - UHD_LOGGER_INFO("E300") << "Got unknown request?!"; - - socket->send_to(asio::buffer(in_buff, sizeof(sensor_transaction_t)), *endpoint); - } - } - catch(const std::exception &ex) - { - UHD_LOGGER_ERROR("E300") << "e300_sensor_tunnel exit " << name << " " << ex.what() ; - } - catch(...) - { - UHD_LOGGER_ERROR("E300") << "e300_sensor_tunnel exit " << name ; - } - UHD_LOGGER_INFO("E300") << "e300_sensor_tunnel exit " << name; - *running = false; -} - -static void e300_i2c_tunnel( - const std::string &name, - boost::shared_ptr<asio::ip::udp::socket> socket, - uhd::usrp::e300::i2c::sptr i2c, - asio::ip::udp::endpoint *endpoint, - bool *running -) -{ - UHD_ASSERT_THROW(i2c); - asio::ip::udp::endpoint _endpoint; - try - { - while (*running) - { - uint8_t in_buff[sizeof(uhd::usrp::e300::i2c_transaction_t)]; - - const size_t num_bytes = socket->receive_from(asio::buffer(in_buff), *endpoint); - - if (num_bytes < sizeof(uhd::usrp::e300::i2c_transaction_t)) { - std::cout << "Received short packet: " << num_bytes << std::endl; - continue; - } - - uhd::usrp::e300::i2c_transaction_t *in = - reinterpret_cast<uhd::usrp::e300::i2c_transaction_t *>(in_buff); - - // byte addressed accesses go through here - if(in->type & i2c::ONEBYTE) { - if(in->type & i2c::WRITE) { - i2c->set_i2c_reg8( - in->addr, - uhd::ntohx<uint16_t>(in->reg), in->data); - } else { - in->data = i2c->get_i2c_reg8(in->addr, uhd::ntohx<uint16_t>(in->reg)); - socket->send_to(asio::buffer(in_buff, sizeof(in_buff)), *endpoint); - } - - // 2 byte addressed accesses go through here - } else if (in->type & i2c::TWOBYTE) { - if(in->type & i2c::WRITE) { - i2c->set_i2c_reg16( - in->addr, - uhd::ntohx<uint16_t>(in->reg), in->data); - } else { - in->data = i2c->get_i2c_reg16(in->addr, uhd::ntohx<uint16_t>(in->reg)); - socket->send_to(asio::buffer(in_buff, sizeof(in_buff)), *endpoint); - } - - } else { - UHD_LOGGER_ERROR("E300") << "e300_i2c_tunnel could not handle message." ; - } - } - } - catch(const std::exception &ex) - { - UHD_LOGGER_ERROR("E300") << "e300_i2c_tunnel exit " << name << " " << ex.what() ; - } - catch(...) - { - UHD_LOGGER_ERROR("E300") << "e300_i2c_tunnel exit " << name ; - } - UHD_LOGGER_INFO("E300") << "e300_i2c_tunnel exit " << name; - *running = false; -} - - - - -class network_server_impl : public network_server -{ -public: - network_server_impl(const uhd::device_addr_t &device_addr); - virtual ~network_server_impl(void); - void run(void); - -private: - struct xports_t - { - uhd::transport::zero_copy_if::sptr send_ctrl_xport; - uhd::transport::zero_copy_if::sptr recv_ctrl_xport; - uhd::transport::zero_copy_if::sptr tx_data_xport; - uhd::transport::zero_copy_if::sptr tx_flow_xport; - uhd::transport::zero_copy_if::sptr rx_data_xport; - uhd::transport::zero_copy_if::sptr rx_flow_xport; - }; - -private: - void _run_server( - const std::string &port, - const std::string &what, - const size_t fe); - -private: - boost::shared_ptr<e300_fifo_interface> _fifo_iface; - xports_t _xports[2]; - boost::shared_ptr<ad9361_ctrl> _codec_ctrl; - boost::shared_ptr<global_regs> _global_regs; - boost::shared_ptr<e300_sensor_manager> _sensor_manager; - boost::shared_ptr<e300_eeprom_manager> _eeprom_manager; -}; - -network_server_impl::~network_server_impl(void) -{ -} - -/*********************************************************************** - * The UDP server itself - **********************************************************************/ -void network_server_impl::_run_server( - const std::string &port, - const std::string &what, - const size_t fe) -{ - asio::io_service io_service; - asio::ip::udp::resolver resolver(io_service); - asio::ip::udp::resolver::query query(asio::ip::udp::v4(), "0.0.0.0", port); - asio::ip::udp::endpoint endpoint = *resolver.resolve(query); - - //boost::shared_ptr<asio::ip::udp::acceptor> acceptor(new asio::ip::udp::acceptor(io_service, endpoint)); - while (not boost::this_thread::interruption_requested()) - { - UHD_LOGGER_INFO("E300") << "e300 run server on port " << port << " for " << what; - try - { - //while (not wait_for_recv_ready(acceptor->native(), 100)) - //{ - // if (boost::this_thread::interruption_requested()) return; - //} - boost::shared_ptr<asio::ip::udp::socket> socket; - socket.reset(new asio::ip::udp::socket(io_service, endpoint)); - //acceptor->accept(*socket); - UHD_LOGGER_INFO("E300") << "e300 socket accept on port " << port << " for " << what; - //asio::ip::udp::no_delay option(true); - //socket->set_option(option); - boost::thread_group tg; - bool running = true; - xports_t &perif = _xports[fe]; - if (what == "RX") { - tg.create_thread(boost::bind(&e300_recv_tunnel, "RX data tunnel", perif.rx_data_xport, socket, &endpoint, &running)); - tg.create_thread(boost::bind(&e300_send_tunnel, "RX flow tunnel", socket, perif.rx_flow_xport, &endpoint, &running)); - } - if (what == "TX") { - tg.create_thread(boost::bind(&e300_recv_tunnel, "TX flow tunnel", perif.tx_flow_xport, socket, &endpoint, &running)); - tg.create_thread(boost::bind(&e300_send_tunnel, "TX data tunnel", socket, perif.tx_data_xport, &endpoint, &running)); - } - if (what == "CTRL") { - tg.create_thread(boost::bind(&e300_recv_tunnel, "response tunnel", perif.recv_ctrl_xport, socket, &endpoint, &running)); - tg.create_thread(boost::bind(&e300_send_tunnel, "control tunnel", socket, perif.send_ctrl_xport, &endpoint, &running)); - } - if (what == "CODEC") { - tg.create_thread(boost::bind(&e300_codec_ctrl_tunnel, "CODEC tunnel", socket, _codec_ctrl, &endpoint, &running)); - } - if (what == "I2C") { - tg.create_thread(boost::bind(&e300_i2c_tunnel, "I2C tunnel", socket, _eeprom_manager->get_i2c_sptr(), &endpoint, &running)); - } - if (what == "GREGS") { - tg.create_thread(boost::bind(&e300_global_regs_tunnel, "GREGS tunnel", socket, _global_regs, &endpoint, &running)); - } - if (what == "SENSOR") { - tg.create_thread(boost::bind(&e300_sensor_tunnel, "SENSOR tunnel", socket, _sensor_manager, &endpoint, &running)); - } - - tg.join_all(); - socket->close(); - socket.reset(); - } - catch(...){} - } -} - -void network_server_impl::run() -{ - for(;;) - { - boost::thread_group tg; - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_RX_PORT0, "RX",0)); - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_TX_PORT0, "TX",0)); - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_CTRL_PORT0, "CTRL",0)); - - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_RX_PORT1, "RX",1)); - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_TX_PORT1, "TX",1)); - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_CTRL_PORT1, "CTRL",1)); - - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_SENSOR_PORT, "SENSOR", 0 /*don't care */)); - - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_CODEC_PORT, "CODEC", 0 /*don't care */)); - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_GREGS_PORT, "GREGS", 0 /*don't care */)); - tg.create_thread(boost::bind(&network_server_impl::_run_server, this, E300_SERVER_I2C_PORT, "I2C", 0 /*don't care */)); - tg.join_all(); - } -} -network_server_impl::network_server_impl(const uhd::device_addr_t &device_addr) -{ - _eeprom_manager = boost::make_shared<e300_eeprom_manager>(i2c::make_i2cdev(E300_I2CDEV_DEVICE)); - if (not device_addr.has_key("no_reload_fpga")) { - // Load FPGA image if provided via args - if (device_addr.has_key("fpga")) { - common::load_fpga_image(device_addr["fpga"]); - // Else load the FPGA image based on the product ID - } else { - //extract the FPGA path for the e300 - const uint16_t pid = boost::lexical_cast<uint16_t>( - _eeprom_manager->get_mb_eeprom()["product"]); - std::string fpga_image; - switch(e300_eeprom_manager::get_mb_type(pid)) { - case e300_eeprom_manager::USRP_E310_SG1_MB: - fpga_image = find_image_path(E310_SG1_FPGA_FILE_NAME); - break; - case e300_eeprom_manager::USRP_E310_SG3_MB: - fpga_image = find_image_path(E310_SG3_FPGA_FILE_NAME); - break; - case e300_eeprom_manager::USRP_E300_MB: - fpga_image = find_image_path(E300_FPGA_FILE_NAME); - break; - case e300_eeprom_manager::UNKNOWN: - default: - UHD_LOGGER_WARNING("E300") << "Unknown motherboard type, loading e300 image." - ; - fpga_image = find_image_path(E300_FPGA_FILE_NAME); - break; - } - common::load_fpga_image(fpga_image); - } - } - - uhd::transport::zero_copy_xport_params ctrl_xport_params; - ctrl_xport_params.recv_frame_size = e300::DEFAULT_CTRL_FRAME_SIZE; - ctrl_xport_params.num_recv_frames = e300::DEFAULT_CTRL_NUM_FRAMES; - ctrl_xport_params.send_frame_size = e300::DEFAULT_CTRL_FRAME_SIZE; - ctrl_xport_params.num_send_frames = e300::DEFAULT_CTRL_NUM_FRAMES; - - uhd::transport::zero_copy_xport_params data_xport_params; - data_xport_params.recv_frame_size = device_addr.cast<size_t>("recv_frame_size", e300::DEFAULT_RX_DATA_FRAME_SIZE); - data_xport_params.num_recv_frames = device_addr.cast<size_t>("num_recv_frames", e300::DEFAULT_RX_DATA_NUM_FRAMES); - data_xport_params.send_frame_size = device_addr.cast<size_t>("send_frame_size", e300::DEFAULT_TX_DATA_FRAME_SIZE); - data_xport_params.num_send_frames = device_addr.cast<size_t>("num_send_frames", e300::DEFAULT_TX_DATA_NUM_FRAMES); - // until we figure out why this goes wrong we'll keep this hack around - data_xport_params.recv_frame_size = - std::min(e300::MAX_NET_RX_DATA_FRAME_SIZE, data_xport_params.recv_frame_size); - data_xport_params.send_frame_size = - std::min(e300::MAX_NET_TX_DATA_FRAME_SIZE, data_xport_params.send_frame_size); - - - e300_fifo_config_t fifo_cfg; - try { - fifo_cfg = e300_read_sysfs(); - } catch (uhd::lookup_error &e) { - throw uhd::runtime_error("Failed to get driver parameters from sysfs."); - } - _fifo_iface = e300_fifo_interface::make(fifo_cfg); - _global_regs = global_regs::make(_fifo_iface->get_global_regs_base()); - - // static mapping, boooohhhhhh - _xports[0].send_ctrl_xport = _fifo_iface->make_send_xport(E300_R0_CTRL_STREAM, ctrl_xport_params); - _xports[0].recv_ctrl_xport = _fifo_iface->make_recv_xport(E300_R0_CTRL_STREAM, ctrl_xport_params); - _xports[0].tx_data_xport = _fifo_iface->make_send_xport(E300_R0_TX_DATA_STREAM, data_xport_params); - _xports[0].tx_flow_xport = _fifo_iface->make_recv_xport(E300_R0_TX_DATA_STREAM, ctrl_xport_params); - _xports[0].rx_data_xport = _fifo_iface->make_recv_xport(E300_R0_RX_DATA_STREAM, data_xport_params); - _xports[0].rx_flow_xport = _fifo_iface->make_send_xport(E300_R0_RX_DATA_STREAM, ctrl_xport_params); - - _xports[1].send_ctrl_xport = _fifo_iface->make_send_xport(E300_R1_CTRL_STREAM, ctrl_xport_params); - _xports[1].recv_ctrl_xport = _fifo_iface->make_recv_xport(E300_R1_CTRL_STREAM, ctrl_xport_params); - _xports[1].tx_data_xport = _fifo_iface->make_send_xport(E300_R1_TX_DATA_STREAM, data_xport_params); - _xports[1].tx_flow_xport = _fifo_iface->make_recv_xport(E300_R1_TX_DATA_STREAM, ctrl_xport_params); - _xports[1].rx_data_xport = _fifo_iface->make_recv_xport(E300_R1_RX_DATA_STREAM, data_xport_params); - _xports[1].rx_flow_xport = _fifo_iface->make_send_xport(E300_R1_RX_DATA_STREAM, ctrl_xport_params); - - ad9361_params::sptr client_settings = boost::make_shared<e300_ad9361_client_t>(); - _codec_ctrl = ad9361_ctrl::make_spi(client_settings, spi::make(E300_SPIDEV_DEVICE), 1); - // This is horrible ... why do I have to sleep here? - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - _sensor_manager = e300_sensor_manager::make_local(_global_regs); -} - -}}} // namespace - -using namespace uhd::usrp::e300; - -network_server::sptr network_server::make(const uhd::device_addr_t &device_addr) -{ - return sptr(new network_server_impl(device_addr)); -} - -#else - -using namespace uhd::usrp::e300; - -network_server::sptr network_server::make(const uhd::device_addr_t &) -{ - throw uhd::assertion_error("network_server::make() !E300_NATIVE"); -} -#endif diff --git a/host/lib/usrp/e300/e300_network.hpp b/host/lib/usrp/e300/e300_network.hpp deleted file mode 100644 index caa25b0ad..000000000 --- a/host/lib/usrp/e300/e300_network.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_NETWORK_HPP -#define INCLUDED_E300_NETWORK_HPP - -#include <string> -#include <uhd/utils/noncopyable.hpp> - -#include <uhd/device.hpp> - - -static const std::string E310_FPGA_FILE_NAME = "usrp_e310_fpga.bit"; -static const std::string E300_FPGA_FILE_NAME = "usrp_e300_fpga.bit"; - -namespace uhd { namespace usrp { namespace e300 { - -class UHD_API network_server : uhd::noncopyable -{ -public: - typedef boost::shared_ptr<network_server> sptr; - virtual void run(void) = 0; - - static sptr make(const uhd::device_addr_t &device_addr); -}; - - -}}} -#endif // INCLUDED_E300_NETWORK_HPP diff --git a/host/lib/usrp/e300/e300_regs.hpp b/host/lib/usrp/e300/e300_regs.hpp deleted file mode 100644 index 88d58907b..000000000 --- a/host/lib/usrp/e300/e300_regs.hpp +++ /dev/null @@ -1,25 +0,0 @@ -// -// Copyright 2012-2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_REGS_HPP -#define INCLUDED_E300_REGS_HPP - -#include <stdint.h> -#include <uhd/config.hpp> - -static const uint32_t VCRX_V2 = 15; -static const uint32_t VCRX_V1 = 14; -static const uint32_t VCTXRX_V2 = 13; -static const uint32_t VCTXRX_V1 = 12; -static const uint32_t TX_ENABLEB = 11; -static const uint32_t TX_ENABLEA = 10; -static const uint32_t RXC_BANDSEL = 8; -static const uint32_t RXB_BANDSEL = 6; -static const uint32_t RX_BANDSEL = 3; -static const uint32_t TX_BANDSEL = 0; - -#endif /* INCLUDED_E300_REGS_HPP */ diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp deleted file mode 100644 index 5692a138e..000000000 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp +++ /dev/null @@ -1,285 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "e300_remote_codec_ctrl.hpp" - -#include <stdint.h> -#include <uhd/exception.hpp> -#include <uhd/utils/byteswap.hpp> -#include <cstring> -#include <iostream> - -namespace uhd { namespace usrp { namespace e300 { - -class e300_remote_codec_ctrl_impl : public e300_remote_codec_ctrl -{ -public: - e300_remote_codec_ctrl_impl(uhd::transport::zero_copy_if::sptr xport) : _xport(xport) - { - } - - virtual ~e300_remote_codec_ctrl_impl(void) - { - } - - - double set_gain(const std::string &which, const double value) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_SET_GAIN); - if (which == "TX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX1); - else if (which == "TX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX2); - else if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - _args.gain = value; - - _transact(); - return _retval.gain; - } - - double set_clock_rate(const double rate) - { - _clear(); - _args.action = uhd::htonx<uint32_t>( - transaction_t::ACTION_SET_CLOCK_RATE); - _args.which = uhd::htonx<uint32_t>( - transaction_t::CHAIN_NONE); /*Unused*/ - _args.rate = rate; - - _transact(); - return _retval.gain; - } - - void set_active_chains(bool tx1, bool tx2, bool rx1, bool rx2) - { - _clear(); - _args.action = uhd::htonx<uint32_t>( - transaction_t::ACTION_SET_ACTIVE_CHANS); - /*Unused*/ - _args.which = uhd::htonx<uint32_t>( - transaction_t::CHAIN_NONE); - _args.bits = uhd::htonx<uint32_t>( - (tx1 ? (1<<0) : 0) | - (tx2 ? (1<<1) : 0) | - (rx1 ? (1<<2) : 0) | - (rx2 ? (1<<3) : 0)); - - _transact(); - } - - double tune(const std::string &which, const double value) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_TUNE); - if (which == "TX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX1); - else if (which == "TX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX2); - else if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - _args.freq = value; - - _transact(); - return _retval.freq; - } - - double get_freq(const std::string &which) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_GET_FREQ); - if (which == "TX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX1); - else if (which == "TX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX2); - else if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - - _transact(); - return _retval.freq; - } - - void data_port_loopback(const bool on) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_SET_LOOPBACK); - _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_NONE); /*Unused*/ - _args.bits = uhd::htonx<uint32_t>(on ? 1 : 0); - - _transact(); - } - - sensor_value_t get_rssi(const std::string &which) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_GET_RSSI); - if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - _args.bits = uhd::htonx<uint32_t>(0); - - _transact(); - return sensor_value_t("RSSI", _retval.rssi, "dB"); - } - - sensor_value_t get_temperature() - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_GET_TEMPERATURE); - _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_NONE); /*Unused*/ - _args.bits = uhd::htonx<uint32_t>(0); - - _transact(); - return sensor_value_t("temp", _retval.temp, "C"); - } - - void set_dc_offset_auto(const std::string &which, const bool on) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_SET_DC_OFFSET_AUTO); - if (which == "TX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX1); - else if (which == "TX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX2); - else if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - _args.use_dc_correction = on ? 1 : 0; - - _transact(); - } - - void set_iq_balance_auto(const std::string &which, const bool on) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_SET_IQ_BALANCE_AUTO); - if (which == "TX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX1); - else if (which == "TX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX2); - else if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - _args.use_iq_correction = on ? 1 : 0; - - _transact(); - } - - void set_agc(const std::string &which, bool enable) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_SET_AGC); - if (which == "TX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX1); - else if (which == "TX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX2); - else if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - _args.use_agc = enable ? 1 : 0; - - _transact(); - } - - void set_agc_mode(const std::string &which, const std::string &mode) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_SET_AGC_MODE); - - if (which == "TX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX1); - else if (which == "TX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX2); - else if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - - if(mode == "slow") { - _args.agc_mode = 0; - } else if (mode == "fast") { - _args.agc_mode = 1; - } else { - throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect agc mode."); - } - - _transact(); - } - - //! set the filter bandwidth for the frontend's analog low pass - double set_bw_filter(const std::string &which, const double bw) - { - _clear(); - _args.action = uhd::htonx<uint32_t>(transaction_t::ACTION_SET_BW); - if (which == "TX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX1); - else if (which == "TX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_TX2); - else if (which == "RX1") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX1); - else if (which == "RX2") _args.which = uhd::htonx<uint32_t>(transaction_t::CHAIN_RX2); - else throw std::runtime_error("e300_remote_codec_ctrl_impl incorrect chain string."); - _args.bw = bw; - - _transact(); - return _retval.bw; - } - - //! List all available filters by name - std::vector<std::string> get_filter_names(const std::string &) - { - return std::vector<std::string>(); - } - - //! Return a list of all filters - filter_info_base::sptr get_filter(const std::string &, const std::string &) - { - UHD_THROW_INVALID_CODE_PATH(); - } - - //! Write back a filter - void set_filter(const std::string &, const std::string &, const filter_info_base::sptr) - { - UHD_LOGGER_WARNING("E300") << "Attempting to set filter on E300 in network mode." ; - } - - void output_digital_test_tone(UHD_UNUSED(bool enb)) - { - UHD_THROW_INVALID_CODE_PATH(); - } - - void set_timing_mode(UHD_UNUSED(const std::string &timing_mode)) - { - UHD_THROW_INVALID_CODE_PATH(); - } - -private: - void _transact() { - { - uhd::transport::managed_send_buffer::sptr buff = _xport->get_send_buff(10.0); - if (not buff or buff->size() < sizeof(_args)) - throw std::runtime_error("e300_remote_codec_ctrl_impl send timeout"); - std::memcpy(buff->cast<void *>(), &_args, sizeof(_args)); - buff->commit(sizeof(_args)); - } - { - uhd::transport::managed_recv_buffer::sptr buff = _xport->get_recv_buff(10.0); - if (not buff or buff->size() < sizeof(_retval)) - throw std::runtime_error("e300_remote_codec_ctrl_impl recv timeout"); - std::memcpy(&_retval, buff->cast<const void *>(), sizeof(_retval)); - } - - if (_args.action != _retval.action) - throw std::runtime_error("e300_remote_codec_ctrl_impl transaction failed."); - } - - void _clear() { - _args.action = 0; - _args.which = 0; - _args.bits = 0; - _retval.action = 0; - _retval.which = 0; - _retval.bits = 0; - } - - uhd::transport::zero_copy_if::sptr _xport; - transaction_t _args; - transaction_t _retval; -}; - -ad9361_ctrl::sptr e300_remote_codec_ctrl::make(uhd::transport::zero_copy_if::sptr xport) -{ - return sptr(new e300_remote_codec_ctrl_impl(xport)); -} - -}}}; diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp deleted file mode 100644 index 9c9e16672..000000000 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_REMOTE_CODEC_CTRL_HPP -#define INCLUDED_E300_REMOTE_CODEC_CTRL_HPP - -#include <uhd/transport/zero_copy.hpp> -#include <uhdlib/usrp/common/ad9361_ctrl.hpp> - -namespace uhd { namespace usrp { namespace e300 { - -class e300_remote_codec_ctrl : public uhd::usrp::ad9361_ctrl -{ -public: - struct transaction_t { - uint32_t action; - uint32_t which; - union { - double rate; - double gain; - double freq; - double rssi; - double temp; - double bw; - uint32_t use_dc_correction; - uint32_t use_iq_correction; - uint32_t use_agc; - uint32_t agc_mode; - uint64_t bits; - }; - - //Actions - static const uint32_t ACTION_SET_GAIN = 10; - static const uint32_t ACTION_SET_CLOCK_RATE = 11; - static const uint32_t ACTION_SET_ACTIVE_CHANS = 12; - static const uint32_t ACTION_TUNE = 13; - static const uint32_t ACTION_SET_LOOPBACK = 14; - static const uint32_t ACTION_GET_RSSI = 15; - static const uint32_t ACTION_GET_TEMPERATURE = 16; - static const uint32_t ACTION_SET_DC_OFFSET_AUTO = 17; - static const uint32_t ACTION_SET_IQ_BALANCE_AUTO = 18; - static const uint32_t ACTION_SET_AGC = 19; - static const uint32_t ACTION_SET_AGC_MODE = 20; - static const uint32_t ACTION_SET_BW = 21; - static const uint32_t ACTION_GET_FREQ = 22; - - //Values for "which" - static const uint32_t CHAIN_NONE = 0; - static const uint32_t CHAIN_TX1 = 1; - static const uint32_t CHAIN_TX2 = 2; - static const uint32_t CHAIN_RX1 = 3; - static const uint32_t CHAIN_RX2 = 4; - }; - - static sptr make(uhd::transport::zero_copy_if::sptr xport); -}; - -}}}; - -#endif /* INCLUDED_E300_REMOTE_CODEC_CTRL_HPP */ diff --git a/host/lib/usrp/e300/e300_sensor_manager.cpp b/host/lib/usrp/e300/e300_sensor_manager.cpp deleted file mode 100644 index fda1f3f80..000000000 --- a/host/lib/usrp/e300/e300_sensor_manager.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include "e300_sensor_manager.hpp" - -#include <boost/thread.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/format.hpp> - -#include <cstring> -#include <uhd/exception.hpp> -#include <uhd/utils/byteswap.hpp> - -namespace uhd { namespace usrp { namespace e300 { - -class e300_sensor_proxy : public e300_sensor_manager -{ -public: - e300_sensor_proxy( - uhd::transport::zero_copy_if::sptr xport) : _xport(xport) - { - } - - std::vector<std::string> get_sensors() - { - return boost::assign::list_of("temp")("ref_locked"); - } - - uhd::sensor_value_t get_sensor(const std::string &key) - { - if (key == "temp") - return get_mb_temp(); - else if (key == "ref_locked") - return get_ref_lock(); - else - throw uhd::lookup_error( - str(boost::format("Invalid sensor %s requested.") % key)); - } - - uhd::sensor_value_t get_mb_temp(void) - { - boost::mutex::scoped_lock(_mutex); - sensor_transaction_t transaction; - transaction.which = uhd::htonx<uint32_t>(ZYNQ_TEMP); - { - uhd::transport::managed_send_buffer::sptr buff - = _xport->get_send_buff(1.0); - if (not buff or buff->size() < sizeof(transaction)) { - throw uhd::runtime_error("sensor proxy send timeout"); - } - std::memcpy( - buff->cast<void *>(), - &transaction, - sizeof(transaction)); - buff->commit(sizeof(transaction)); - } - { - uhd::transport::managed_recv_buffer::sptr buff - = _xport->get_recv_buff(1.0); - - if (not buff or buff->size() < sizeof(transaction)) - throw uhd::runtime_error("sensor proxy recv timeout"); - - std::memcpy( - &transaction, - buff->cast<const void *>(), - sizeof(transaction)); - } - UHD_ASSERT_THROW(uhd::ntohx<uint32_t>(transaction.which) == ZYNQ_TEMP); - // TODO: Use proper serialization here ... - return sensor_value_t( - "temp", - e300_sensor_manager::unpack_float_from_uint32_t( - uhd::ntohx(transaction.value)), - "C"); - } - - uhd::sensor_value_t get_ref_lock(void) - { - boost::mutex::scoped_lock(_mutex); - sensor_transaction_t transaction; - transaction.which = uhd::htonx<uint32_t>(REF_LOCK); - { - uhd::transport::managed_send_buffer::sptr buff - = _xport->get_send_buff(1.0); - if (not buff or buff->size() < sizeof(transaction)) { - throw uhd::runtime_error("sensor proxy send timeout"); - } - std::memcpy( - buff->cast<void *>(), - &transaction, - sizeof(transaction)); - buff->commit(sizeof(transaction)); - } - { - uhd::transport::managed_recv_buffer::sptr buff - = _xport->get_recv_buff(1.0); - - if (not buff or buff->size() < sizeof(transaction)) - throw uhd::runtime_error("sensor proxy recv timeout"); - - std::memcpy( - &transaction, - buff->cast<const void *>(), - sizeof(transaction)); - } - UHD_ASSERT_THROW(uhd::ntohx<uint32_t>(transaction.which) == REF_LOCK); - // TODO: Use proper serialization here ... - return sensor_value_t("Ref", (uhd::ntohx(transaction.value) > 0), "locked", "unlocked"); - } - -private: - uhd::transport::zero_copy_if::sptr _xport; - boost::mutex _mutex; -}; - -}}} // namespace - -using namespace uhd::usrp::e300; - -e300_sensor_manager::sptr e300_sensor_manager::make_proxy( - uhd::transport::zero_copy_if::sptr xport) -{ - return sptr(new e300_sensor_proxy(xport)); -} - -#ifdef E300_NATIVE -#include "e300_fifo_config.hpp" - -namespace uhd { namespace usrp { namespace e300 { - -static const std::string E300_TEMP_SYSFS = "iio:device0"; - -class e300_sensor_local : public e300_sensor_manager -{ -public: - e300_sensor_local(global_regs::sptr global_regs) : - _global_regs(global_regs) - { - } - - std::vector<std::string> get_sensors() - { - return boost::assign::list_of("temp")("ref_locked"); - } - - uhd::sensor_value_t get_sensor(const std::string &key) - { - if (key == "temp") - return get_mb_temp(); - else if (key == "ref_locked") - return get_ref_lock(); - else - throw uhd::lookup_error( - str(boost::format("Invalid sensor %s requested.") % key)); - } - - uhd::sensor_value_t get_mb_temp(void) - { - double scale = std::stod( - e300_get_sysfs_attr(E300_TEMP_SYSFS, "in_temp0_scale")); - unsigned long raw = std::stoul( - e300_get_sysfs_attr(E300_TEMP_SYSFS, "in_temp0_raw")); - unsigned long offset = std::stoul( - e300_get_sysfs_attr(E300_TEMP_SYSFS, "in_temp0_offset")); - return sensor_value_t("temp", (raw + offset) * scale / 1000, "C"); - } - - uhd::sensor_value_t get_ref_lock(void) - { - //PPSLOOP_LOCKED_MASK is asserted in the following cases: - //- (Time source = GPS or External) AND (Loop is locked and is in fine adj mode) - //- Time source is Internal - static const uint32_t PPSLOOP_LOCKED_MASK = 0x04; - static const uint32_t REFPLL_LOCKED_MASK = 0x20; - - const uint32_t status = - _global_regs->peek32(global_regs::RB32_CORE_MISC); - bool ref_locked = (status & PPSLOOP_LOCKED_MASK) && (status & REFPLL_LOCKED_MASK); - - return sensor_value_t("Ref", ref_locked, "locked", "unlocked"); - } - -private: - global_regs::sptr _global_regs; -}; -}}} - -using namespace uhd::usrp::e300; -e300_sensor_manager::sptr e300_sensor_manager::make_local( - global_regs::sptr global_regs) -{ - return sptr(new e300_sensor_local(global_regs)); -} - -#else -using namespace uhd::usrp::e300; -e300_sensor_manager::sptr e300_sensor_manager::make_local( - global_regs::sptr) -{ - throw uhd::assertion_error("e300_sensor_manager::make_local() !E300_NATIVE"); -} -#endif diff --git a/host/lib/usrp/e300/e300_sensor_manager.hpp b/host/lib/usrp/e300/e300_sensor_manager.hpp deleted file mode 100644 index 8ed09b1eb..000000000 --- a/host/lib/usrp/e300/e300_sensor_manager.hpp +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright 2014-2015 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include <uhd/utils/noncopyable.hpp> -#include <stdint.h> - -#include <uhd/transport/zero_copy.hpp> -#include <uhd/types/sensors.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/usrp/gps_ctrl.hpp> -#include "e300_global_regs.hpp" - -#ifndef INCLUDED_E300_SENSOR_MANAGER_HPP -#define INCLUDED_E300_SENSOR_MANAGER_HPP - -namespace uhd { namespace usrp { namespace e300 { - -struct sensor_transaction_t { - uint32_t which; - union { - uint32_t value; - uint32_t value64; - }; -}; - - - -enum sensor {ZYNQ_TEMP=0, REF_LOCK=4}; - -class e300_sensor_manager : uhd::noncopyable -{ -public: - typedef boost::shared_ptr<e300_sensor_manager> sptr; - - virtual ~e300_sensor_manager() {}; - - virtual uhd::sensor_value_t get_sensor(const std::string &key) = 0; - virtual std::vector<std::string> get_sensors(void) = 0; - - virtual uhd::sensor_value_t get_mb_temp(void) = 0; - virtual uhd::sensor_value_t get_ref_lock(void) = 0; - - - static sptr make_proxy(uhd::transport::zero_copy_if::sptr xport); - static sptr make_local(global_regs::sptr global_regs); - - // Note: This is a hack - static uint32_t pack_float_in_uint32_t(const float &v) - { - const uint32_t *cast = reinterpret_cast<const uint32_t*>(&v); - return *cast; - } - - static float unpack_float_from_uint32_t(const uint32_t &v) - { - const float *cast = reinterpret_cast<const float*>(&v); - return *cast; - } -}; - - -}}} // namespace - -#endif // INCLUDED_E300_SENSOR_MANAGER_HPP diff --git a/host/lib/usrp/e300/e300_spi.cpp b/host/lib/usrp/e300/e300_spi.cpp deleted file mode 100644 index e0f25c22f..000000000 --- a/host/lib/usrp/e300/e300_spi.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#include <uhd/config.hpp> -#include <uhd/exception.hpp> -#include "e300_spi.hpp" - -#ifdef E300_NATIVE -#include <boost/thread.hpp> -#include <boost/format.hpp> - -#include <fcntl.h> -#include <sys/ioctl.h> -#include <linux/types.h> -#include <linux/spi/spidev.h> - -namespace uhd { namespace usrp { namespace e300 { - -class spidev_impl : public spi -{ -public: - - spidev_impl(const std::string &device) - : _mode(SPI_CPHA), - _speed(2000000), - _bits(8), - _delay(0) - { - int ret; - _fd = open(device.c_str(), O_RDWR); - if (_fd < 0) - throw uhd::runtime_error(str(boost::format("Could not open spidev device %s") % device)); - - ret = ioctl(_fd, SPI_IOC_WR_MODE, &_mode); - if (ret == -1) - throw uhd::runtime_error("Could not set spidev mode"); - - ret = ioctl(_fd, SPI_IOC_RD_MODE, &_mode); - if (ret == -1) - throw uhd::runtime_error("Could not get spidev mode"); - - ret = ioctl(_fd, SPI_IOC_WR_BITS_PER_WORD, &_bits); - if (ret == -1) - throw uhd::runtime_error("Could not set spidev bits per word"); - - ret = ioctl(_fd, SPI_IOC_RD_BITS_PER_WORD, &_bits); - if (ret == -1) - throw uhd::runtime_error("Could not get spidev bits per word"); - - ret = ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &_speed); - if (ret == -1) - throw uhd::runtime_error("Could not set spidev max speed"); - - ret = ioctl(_fd, SPI_IOC_RD_MAX_SPEED_HZ, &_speed); - if (ret == -1) - throw uhd::runtime_error("Could not get spidev max speed"); - } - - virtual ~spidev_impl() - { - close(_fd); - } - - uint32_t transact_spi(int, const uhd::spi_config_t &, - uint32_t data, size_t num_bits, - bool) - { - int ret(0); - struct spi_ioc_transfer tr; - - uint8_t *tx_data = reinterpret_cast<uint8_t *>(&data); - - - UHD_ASSERT_THROW(num_bits == 24); - uint8_t tx[] = {tx_data[2], tx_data[1], tx_data[0]}; - - uint8_t rx[3]; - tr.tx_buf = (unsigned long) &tx[0]; - tr.rx_buf = (unsigned long) &rx[0]; - tr.len = num_bits >> 3; - tr.bits_per_word = _bits; - tr.tx_nbits = 1; - tr.rx_nbits = 1; - tr.speed_hz = _speed; - tr.delay_usecs = _delay; - - ret = ioctl(_fd, SPI_IOC_MESSAGE(1), &tr); - if (ret < 1) - throw uhd::runtime_error("Could not send spidev message"); - - return rx[2]; - } - -private: - int _fd; - uint8_t _mode; - uint32_t _speed; - uint8_t _bits; - uint16_t _delay; -}; - -spi::sptr spi::make(const std::string &device) -{ - return spi::sptr(new spidev_impl(device)); -} -}}}; -#else -namespace uhd { namespace usrp { namespace e300 { - -spi::sptr spi::make(const std::string &) -{ - throw uhd::assertion_error("spi::make() !E300_NATIVE"); -} -}}}; -#endif //E300_NATIVE diff --git a/host/lib/usrp/e300/e300_spi.hpp b/host/lib/usrp/e300/e300_spi.hpp deleted file mode 100644 index 0341ae9c4..000000000 --- a/host/lib/usrp/e300/e300_spi.hpp +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright 2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifndef INCLUDED_E300_SPI_HPP -#define INCLUDED_E300_SPI_HPP - -#include <uhd/types/serial.hpp> - -namespace uhd { namespace usrp { namespace e300 { - -class spi : public virtual uhd::spi_iface -{ -public: - typedef boost::shared_ptr<spi> sptr; - static sptr make(const std::string &device); -}; - -}}}; - -#endif /* INCLUDED_E300_SPI_HPP */ diff --git a/host/lib/usrp/e300/e300_sysfs_hooks.cpp b/host/lib/usrp/e300/e300_sysfs_hooks.cpp deleted file mode 100644 index 81dcff0cb..000000000 --- a/host/lib/usrp/e300/e300_sysfs_hooks.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// -// Copyright 2013-2014 Ettus Research LLC -// Copyright 2018 Ettus Research, a National Instruments Company -// -// SPDX-License-Identifier: GPL-3.0-or-later -// - -#ifdef E300_NATIVE - -#include <cstdio> -#include <cstdlib> -#include <string> -#include <fcntl.h> -#include <unistd.h> - -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/mman.h> - -#include <libudev.h> - -#include <boost/format.hpp> -#include <boost/lexical_cast.hpp> - -#include <uhd/utils/log.hpp> -#include <uhd/exception.hpp> - -static const std::string E300_AXI_FPGA_SYSFS = "40000000.axi-fpga"; -static const std::string E300_XDEV_SYSFS = "f8007000.ps7-dev-cfg"; - -std::string e300_get_sysfs_attr(const std::string &node, const std::string &attr) -{ - udev *udev; - udev_enumerate *enumerate; - udev_list_entry *devices, *dev_list_entry; - udev_device *dev; - std::string retstring; - - udev = udev_new(); - - if (!udev) { - throw uhd::lookup_error("Failed to get udev handle."); - } - - enumerate = udev_enumerate_new(udev); - udev_enumerate_add_match_sysname(enumerate, node.c_str()); - udev_enumerate_scan_devices(enumerate); - devices = udev_enumerate_get_list_entry(enumerate); - - udev_list_entry_foreach(dev_list_entry, devices) - { - const char *path; - - path = udev_list_entry_get_name(dev_list_entry); - dev = udev_device_new_from_syspath(udev, path); - - retstring = udev_device_get_sysattr_value(dev, attr.c_str()); - - udev_device_unref(dev); - - if (retstring.size()) - break; - } - - udev_enumerate_unref(enumerate); - udev_unref(udev); - - return retstring; -} - -static bool e300_fpga_loaded_successfully(void) -{ - return boost::lexical_cast<bool>(e300_get_sysfs_attr(E300_XDEV_SYSFS, "prog_done")); -} - -#include "e300_fifo_config.hpp" -#include <uhd/exception.hpp> - -e300_fifo_config_t e300_read_sysfs(void) -{ - - if (not e300_fpga_loaded_successfully()) - { - throw uhd::runtime_error("E300 FPGA load failed!"); - } - - e300_fifo_config_t config; - - config.buff_length = std::stoul( - e300_get_sysfs_attr(E300_AXI_FPGA_SYSFS, "buffer_length")); - config.ctrl_length = std::stoul( - e300_get_sysfs_attr(E300_AXI_FPGA_SYSFS, "control_length")); - config.phys_addr = std::stoul( - e300_get_sysfs_attr(E300_AXI_FPGA_SYSFS, "phys_addr")); - - return config; -} - -#else //E300_NATIVE - -#include "e300_fifo_config.hpp" -#include <uhd/exception.hpp> - -e300_fifo_config_t e300_read_sysfs(void) -{ - throw uhd::assertion_error("e300_read_sysfs() !E300_NATIVE"); -} - -std::string e300_get_sysfs_attr(const std::string &, const std::string &) -{ - throw uhd::assertion_error("e300_sysfs_attr() !E300_NATIVE"); -} - -#endif //E300_NATIVE diff --git a/host/lib/usrp/e300/e3xx_radio_ctrl_impl.cpp b/host/lib/usrp/e300/e3xx_radio_ctrl_impl.cpp deleted file mode 100644 index 787faf6df..000000000 --- a/host/lib/usrp/e300/e3xx_radio_ctrl_impl.cpp +++ /dev/null @@ -1,770 +0,0 @@ -// -// Copyright 2015-2016 Ettus Research -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#include "e3xx_radio_ctrl_impl.hpp" -#include "e300_defaults.hpp" -#include "e300_regs.hpp" -#include <boost/make_shared.hpp> -#include <uhd/usrp/dboard_iface.hpp> -#include <uhd/rfnoc/node_ctrl_base.hpp> -#include <uhd/utils/log.hpp> -#include <boost/algorithm/string.hpp> -#include <boost/make_shared.hpp> - -using namespace uhd; -using namespace uhd::rfnoc; -using namespace uhd::usrp::e300; -using uhd::usrp::dboard_iface; - -//! mapping of frontend to radio perif index -static const size_t FE0 = 1; -static const size_t FE1 = 0; - -/**************************************************************************** - * Structors - ***************************************************************************/ -UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR(e3xx_radio_ctrl) -{ - UHD_RFNOC_BLOCK_TRACE() << "e3xx_radio_ctrl_impl::ctor() " << std::endl; - - //////////////////////////////////////////////////////////////////// - // Set up peripherals - //////////////////////////////////////////////////////////////////// - for (size_t i = 0; i < _get_num_radios(); i++) { - if (i == 0) { - _spi = spi_core_3000::make(_get_ctrl(i), regs::sr_addr(regs::SPI), regs::RB_SPI); - _spi->set_divider(6); - } - _e3xx_perifs[i].atr = usrp::gpio_atr::gpio_atr_3000::make_write_only(_get_ctrl(i), regs::sr_addr(regs::GPIO)); - _e3xx_perifs[i].leds = usrp::gpio_atr::gpio_atr_3000::make_write_only(_get_ctrl(i), regs::sr_addr(regs::LEDS)); - _e3xx_perifs[i].leds->set_atr_mode(usrp::gpio_atr::MODE_ATR, usrp::gpio_atr::gpio_atr_3000::MASK_SET_ALL); - } - - //////////////////////////////////////////////////////////////////// - // Time source - //////////////////////////////////////////////////////////////////// - _tree->create<std::string>("time_source/value") - .add_coerced_subscriber(boost::bind(&e3xx_radio_ctrl_impl::_update_time_source, this, _1)) - .set(DEFAULT_TIME_SRC); -#ifdef E300_GPSD - static const std::vector<std::string> time_sources = boost::assign::list_of("none")("internal")("external")("gpsdo"); -#else - static const std::vector<std::string> time_sources = boost::assign::list_of("none")("internal")("external"); -#endif - _tree->create<std::vector<std::string> >("time_source/options").set(time_sources); - - //////////////////////////////////////////////////////////////////// - // create RF frontend interfacing - //////////////////////////////////////////////////////////////////// - { - const fs_path codec_path = fs_path("rx_codecs") / "A"; - _tree->create<std::string>(codec_path / "name").set("E3x0 RX dual ADC"); - _tree->create<int>(codec_path / "gains"); //empty cuz gains are in frontend - } - { - const fs_path codec_path = fs_path("tx_codecs") / "A"; - _tree->create<std::string>(codec_path / "name").set("E3x0 TX dual DAC"); - _tree->create<int>(codec_path / "gains"); //empty cuz gains are in frontend - } - - //////////////////////////////////////////////////////////////////// - // internal gpios - //////////////////////////////////////////////////////////////////// - UHD_RFNOC_BLOCK_TRACE() << " Creating internal GPIOs..." << std::endl; - - usrp::gpio_atr::gpio_atr_3000::sptr fp_gpio = usrp::gpio_atr::gpio_atr_3000::make( - get_ctrl_iface(0), - regs::sr_addr(regs::FP_GPIO), - regs::RB_FP_GPIO - ); - for (const auto& attr : usrp::gpio_atr::gpio_attr_map) { - switch (attr.first) { - case usrp::gpio_atr::GPIO_SRC: - _tree->create<std::vector<std::string>>(fs_path("gpio") / "INT0" / 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") / "INT0" / attr.second) - .set(std::vector<std::string>(32, usrp::gpio_atr::default_attr_value_map.at(attr.first))) - .add_coerced_subscriber([this, fp_gpio, 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<uint8_t>(fs_path("gpio") / "INT0" / "READBACK") - .set_publisher([this, fp_gpio](){ - return fp_gpio->read_gpio(); - }); - break; - default: - _tree->create<uint32_t>(fs_path("gpio") / "INT0" / attr.second) - .set(0) - .add_coerced_subscriber([this, fp_gpio, attr](const uint32_t val){ - fp_gpio->set_gpio_attr(attr.first, val); - }); - } - } - - //////////////////////////////////////////////////////////////////// - // Tick rate - //////////////////////////////////////////////////////////////////// - UHD_RFNOC_BLOCK_TRACE() << " Setting tick rate..." << std::endl; - _tree->access<double>("tick_rate") - .add_coerced_subscriber(boost::bind(&e3xx_radio_ctrl_impl::set_rate, this, _1)) - .set_publisher(boost::bind(&e3xx_radio_ctrl_impl::get_rate, this)) - ; -} - -e3xx_radio_ctrl_impl::~e3xx_radio_ctrl_impl() -{ - const std::string _radio_slot = "A"; - // Tear down our part of the tree: - _tree->remove(fs_path("rx_codecs" / _radio_slot)); - _tree->remove(fs_path("tx_codecs" / _radio_slot)); - for (size_t i = 0; i < _get_num_radios(); i++) { - if (_tree->exists(fs_path("tx_dsps") / i)) { - _tree->remove(fs_path("tx_dsps") / i); - } - if (_tree->exists(fs_path("rx_dsps") / i)) { - _tree->remove(fs_path("rx_dsps") / i); - } - } - for (const auto attr : usrp::gpio_atr::gpio_attr_map) { - const auto gpio_fs_path = fs_path("gpio") / "INT0" / attr.second; - if (_tree->exists(gpio_fs_path)) { - _tree->remove(gpio_fs_path); - } - } -} - -/**************************************************************************** - * API calls - ***************************************************************************/ -double e3xx_radio_ctrl_impl::set_rate(double rate) -{ - //UHD_LOGGER_DEBUG("E300") << "Setting SPI divider to " << ceil(rate/AD9361_SPI_RATE) << "\n"; - //_spi->set_divider(ceil(rate/AD9361_SPI_RATE)); // ceil() to prevent less than 1 rounding to 0 - UHD_LOGGER_DEBUG("E300") << "Asking for clock rate " << rate/1e6 << " MHz\n"; - double actual_tick_rate = _codec_ctrl->set_clock_rate(rate); - UHD_LOGGER_DEBUG("E300") << "Actually got clock rate " << actual_tick_rate/1e6 << " MHz\n"; - - actual_tick_rate = radio_ctrl_impl::set_rate(actual_tick_rate); - - if (not check_radio_config()) { - throw std::runtime_error(str( - boost::format("[%s]: Invalid radio configuration.") - % unique_id() - )); - } - - return actual_tick_rate; -} - -/*! Select TX antenna \p for channel \p chan. - */ -void e3xx_radio_ctrl_impl::set_tx_antenna(const std::string &ant, const size_t chan) -{ - std::lock_guard<std::mutex> lock(_mutex); - if (ant != "TX/RX") - throw uhd::value_error("Unknown TX antenna option: " + ant); - - radio_ctrl_impl::set_tx_antenna(ant, chan); -} - -/*! Select RX antenna \p for channel \p chan. - */ -void e3xx_radio_ctrl_impl::set_rx_antenna(const std::string &ant, const size_t chan) -{ - std::lock_guard<std::mutex> lock(_mutex); - if (ant != "TX/RX" and ant != "RX2") - throw uhd::value_error("Unknown RX antenna option: " + ant); - - radio_ctrl_impl::set_rx_antenna(ant, chan); - this->_update_atrs(); - this->_update_atr_leds(_e3xx_perifs[chan].leds, ant); -} - -double e3xx_radio_ctrl_impl::set_tx_frequency(const double freq, const size_t) -{ - return _tree->access<double>(fs_path("dboards/A/tx_frontends/A/freq/value")).set(freq).get(); -} - -double e3xx_radio_ctrl_impl::set_rx_frequency(const double freq, const size_t) -{ - return _tree->access<double>(fs_path("dboards/A/rx_frontends/A/freq/value")).set(freq).get(); -} - -double e3xx_radio_ctrl_impl::set_tx_gain(const double gain, const size_t chan) -{ - const std::string fe_side = (chan == 0) ? "A" : "B"; - double new_gain = _tree->access<double>(fs_path("dboards/A/tx_frontends/" + fe_side + "/gains/PGA/value")).set(gain).get(); - return radio_ctrl_impl::set_tx_gain(new_gain, chan); -} - -double e3xx_radio_ctrl_impl::set_rx_gain(const double gain, const size_t chan) -{ - const std::string fe_side = (chan == 0) ? "A" : "B"; - double new_gain = _tree->access<double>(fs_path("dboards/A/rx_frontends/" + fe_side + "/gains/PGA/value")).set(gain).get(); - return radio_ctrl_impl::set_rx_gain(new_gain, chan); -} - -double e3xx_radio_ctrl_impl::set_rx_bandwidth(const double bandwidth, const size_t chan) -{ - const std::string fe_side = (chan == 0) ? "A" : "B"; - double new_bw = _tree->access<double>(fs_path("dboards/A/rx_frontends/" + fe_side + "/bandwidth/value")).set(bandwidth).get(); - return radio_ctrl_impl::set_rx_bandwidth(new_bw, chan); -} - -double e3xx_radio_ctrl_impl::get_tx_gain(const size_t chan) -{ - const std::string fe_side = (chan == 0) ? "A" : "B"; - return _tree->access<double>(fs_path("dboards/A/tx_frontends/" + fe_side + "/gains/PGA/value")).get(); -} - -double e3xx_radio_ctrl_impl::get_rx_gain(const size_t chan) -{ - const std::string fe_side = (chan == 0) ? "A" : "B"; - return _tree->access<double>(fs_path("dboards/A/rx_frontends/" + fe_side + "/gains/PGA/value")).get(); -} - -double e3xx_radio_ctrl_impl::get_rx_bandwidth(const size_t chan) -{ - const std::string fe_side = (chan == 0) ? "A" : "B"; - return _tree->access<double>(fs_path("dboards/A/rx_frontends/" + fe_side + "/bandwidth/value")).get(); -} - -std::vector<std::string> e3xx_radio_ctrl_impl::get_gpio_banks() const -{ - std::vector<std::string> banks = boost::assign::list_of("INT0"); - return banks; -} - -void e3xx_radio_ctrl_impl::set_gpio_attr( - const std::string &bank, - const std::string &attr, - const uint32_t value, - const uint32_t mask -) { - if (bank == "INT0") { - const uint32_t current = _tree->access<uint32_t>(fs_path("gpio") / bank / attr).get(); - const uint32_t new_value = (current & ~mask) | (value & mask); - _tree->access<uint32_t>(fs_path("gpio") / bank / attr).set(new_value); - return; - } -} - -uint32_t e3xx_radio_ctrl_impl::get_gpio_attr( - const std::string &bank, - const std::string &attr -) { - if (bank == "INT0") { - return uint32_t(_tree->access<uint64_t>(fs_path("gpio") / bank / attr).get()); - } - return 0; -} - -size_t e3xx_radio_ctrl_impl::get_chan_from_dboard_fe(const std::string &fe, const direction_t) -{ - return (fe == "A") ? 0 : 1; -} - -std::string e3xx_radio_ctrl_impl::get_dboard_fe_from_chan(const size_t chan, const direction_t) -{ - return (chan == 0) ? "A" : "B"; -} - -/**************************************************************************** - * Radio control and setup - ***************************************************************************/ -void e3xx_radio_ctrl_impl::setup_radio(uhd::usrp::ad9361_ctrl::sptr safe_codec_ctrl) -{ - { - std::lock_guard<std::mutex> lock(_mutex); - if (_codec_ctrl) { - throw std::runtime_error("Attempting to set up radio twice!"); - } - } - - //////////////////////////////////////////////////////////////////// - // Create timed interface - //////////////////////////////////////////////////////////////////// - _codec_ctrl = safe_codec_ctrl; - _codec_mgr = uhd::usrp::ad936x_manager::make(_codec_ctrl, _get_num_radios()); - - //////////////////////////////////////////////////////////////////// - // setup radios - //////////////////////////////////////////////////////////////////// - for (size_t chan = 0; chan < _get_num_radios(); chan++) { - _setup_radio_channel(chan); - } - // Loopback test - for (size_t chan = 0; chan < _get_num_radios(); chan++) { - _codec_mgr->loopback_self_test( - [this, chan](const uint32_t value){ - this->sr_write(regs::CODEC_IDLE, value, chan); - }, - [this, chan](){ - return this->user_reg_read64(regs::RB_CODEC_READBACK, chan); - } - ); - } - - this->_update_enables(); -} - -void e3xx_radio_ctrl_impl::_setup_radio_channel(const size_t chan) -{ - const fs_path rx_dsp_path = fs_path("rx_dsps") / chan; - _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd") - .add_coerced_subscriber(boost::bind(&radio_ctrl_impl::issue_stream_cmd, this, _1, chan)); - - //////////////////////////////////////////////////////////////////// - // add some dummy nodes on the prop tree (FIXME remove these) - //////////////////////////////////////////////////////////////////// - const fs_path tx_dsp_path = fs_path("tx_dsps") / chan; - _tree->create<double>(tx_dsp_path / "freq/value").set(0.0); - _tree->create<meta_range_t>(tx_dsp_path / "freq/range").set(meta_range_t(0.0, 0.0, 0.0)); - _tree->create<double>(rx_dsp_path / "freq/value").set(0.0); - _tree->create<meta_range_t>(rx_dsp_path / "freq/range").set(meta_range_t(0.0, 0.0, 0.0)); - _tree->create<double>(tx_dsp_path / "rate/value") - .add_coerced_subscriber(boost::bind(&e3xx_radio_ctrl_impl::set_rate, this, _1)) - .set_publisher(boost::bind(&radio_ctrl_impl::get_rate, this)) - ; - _tree->create<double>(rx_dsp_path / "rate/value") - .add_coerced_subscriber(boost::bind(&e3xx_radio_ctrl_impl::set_rate, this, _1)) - .set_publisher(boost::bind(&radio_ctrl_impl::get_rate, this)) - ; - - //////////////////////////////////////////////////////////////////// - // create RF frontend interfacing - //////////////////////////////////////////////////////////////////// - static const std::vector<direction_t> dirs = boost::assign::list_of(RX_DIRECTION)(TX_DIRECTION); - BOOST_FOREACH(direction_t dir, dirs) { - const std::string x = (dir == RX_DIRECTION) ? "rx" : "tx"; - const std::string key = boost::to_upper_copy(x) + std::string(((chan == FE0)? "1" : "2")); - const fs_path rf_fe_path - = fs_path("dboards") / "A" / (x + "_frontends") / ((chan == 0) ? "A" : "B"); - - // This will connect all the AD936x-specific items - _codec_mgr->populate_frontend_subtree( - _tree->subtree(rf_fe_path), key, dir - ); - - // This will connect all the e3xx_radio_ctrl-specific items - _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked") - .set_publisher(boost::bind(&e3xx_radio_ctrl_impl::_get_fe_pll_lock, this, dir == TX_DIRECTION)) - ; - const double freq = _tree->access<double>(rf_fe_path / "freq" / "value") - .add_coerced_subscriber(boost::bind(&e3xx_radio_ctrl_impl::_update_fe_lo_freq, this, key, _1)).get() - ; - // Set frequency in parent (to be used to update ATR values later) - if (dir == RX_DIRECTION) { - radio_ctrl_impl::set_rx_frequency(freq, chan); - } else { - radio_ctrl_impl::set_tx_frequency(freq, chan); - } - - // Antenna Setup - if (dir == RX_DIRECTION) { - static const std::vector<std::string> ants = boost::assign::list_of("TX/RX")("RX2"); - _tree->create<std::vector<std::string> >(rf_fe_path / "antenna" / "options").set(ants); - _tree->create<std::string>(rf_fe_path / "antenna" / "value") - .add_coerced_subscriber(boost::bind(&e3xx_radio_ctrl_impl::set_rx_antenna, this, _1, chan)) - .set_publisher(boost::bind(&e3xx_radio_ctrl_impl::get_rx_antenna, this, chan)); - // Set default in parent (to be used to update ATR values later) - radio_ctrl_impl::set_rx_antenna("RX2", chan); - // Set up LEDs for default antenna - _update_atr_leds(_e3xx_perifs[chan].leds, "RX2"); - } - else if (dir == TX_DIRECTION) { - static const std::vector<std::string> ants(1, "TX/RX"); - _tree->create<std::vector<std::string> >(rf_fe_path / "antenna" / "options").set(ants); - _tree->create<std::string>(rf_fe_path / "antenna" / "value") - .add_coerced_subscriber(boost::bind(&e3xx_radio_ctrl_impl::set_tx_antenna, this, _1, chan)) - .set_publisher(boost::bind(&e3xx_radio_ctrl_impl::get_tx_antenna, this, chan)) - .set("TX/RX"); - } - } -} - -void e3xx_radio_ctrl_impl::_reset_radio(void) -{ - std::lock_guard<std::mutex> lock(_mutex); - _misc.radio_rst = 1; - _update_gpio_state(); - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); - _misc.radio_rst = 0; - _update_gpio_state(); - boost::this_thread::sleep(boost::posix_time::milliseconds(10)); -} - -/**************************************************************************** - * Helpers - ***************************************************************************/ -bool e3xx_radio_ctrl_impl::check_radio_config() -{ - const size_t num_rx = _is_streamer_active(RX_DIRECTION, FE0) + _is_streamer_active(RX_DIRECTION, FE1); - const size_t num_tx = _is_streamer_active(TX_DIRECTION, FE0) + _is_streamer_active(TX_DIRECTION, FE1); - _enforce_tick_rate_limits( - std::max(num_rx, num_tx), - get_tick_rate() - ); - - this->_update_enables(); - return true; -} - -void e3xx_radio_ctrl_impl::_enforce_tick_rate_limits( - const size_t chan_count, - const double tick_rate -) { - const size_t max_chans = 2; - if (chan_count > max_chans) { - throw uhd::value_error(boost::str( - boost::format("cannot not setup %d channels per direction (maximum is %d)") - % chan_count - % max_chans - )); - } else { - const double max_tick_rate = uhd::usrp::ad9361_device_t::AD9361_MAX_CLOCK_RATE / ((chan_count <= 1) ? 1 : 2); - if (tick_rate - max_tick_rate >= 1.0) - { - throw uhd::value_error(boost::str( - boost::format("current master clock rate (%.6f MHz) exceeds maximum possible master clock rate (%.6f MHz) when using %d channels") - % (tick_rate/1e6) - % (max_tick_rate/1e6) - % chan_count - )); - } - // TODO minimum rate check - } -} - -/**************************************************************************** - * Peripheral controls - ***************************************************************************/ -void e3xx_radio_ctrl_impl::_update_fe_lo_freq(const std::string &fe, const double freq) -{ - if (fe[0] == 'R') { - for (size_t i = 0; i < _get_num_radios(); i++) { - radio_ctrl_impl::set_rx_frequency(freq, i); - } - } - if (fe[0] == 'T') { - for (size_t i = 0; i < _get_num_radios(); i++) { - radio_ctrl_impl::set_tx_frequency(freq, i); - } - } - this->_update_atrs(); -} - -void e3xx_radio_ctrl_impl::_update_atrs(void) -{ - for (size_t instance = 0; instance < _get_num_radios(); instance++) - { - // if we're not ready, no point ... - if (not _e3xx_perifs[instance].atr) - return; - - const bool rx_ant_rx2 = get_rx_antenna(instance) == "RX2"; - const double rx_freq = get_rx_frequency(instance); - const double tx_freq = get_tx_frequency(instance); - const bool rx_low_band = rx_freq < 2.6e9; - const bool tx_low_band = tx_freq < 2940.0e6; - - // VCRX - uint32_t vcrx_v1_rxing = 1; - uint32_t vcrx_v2_rxing = 0; - uint32_t vcrx_v1_txing = 1; - uint32_t vcrx_v2_txing = 0; - - if (rx_low_band) { - vcrx_v1_rxing = rx_ant_rx2 ? 0 : 1; - vcrx_v2_rxing = rx_ant_rx2 ? 1 : 0; - vcrx_v1_txing = 0; - vcrx_v2_txing = 1; - } else { - vcrx_v1_rxing = rx_ant_rx2 ? 1 : 0; - vcrx_v2_rxing = rx_ant_rx2 ? 0 : 1; - vcrx_v1_txing = 1; - vcrx_v2_txing = 0; - } - - // VCTX - uint32_t vctxrx_v1_rxing = 0; - uint32_t vctxrx_v2_rxing = 1; - uint32_t vctxrx_v1_txing = 0; - uint32_t vctxrx_v2_txing = 1; - - if (tx_low_band) { - vctxrx_v1_rxing = rx_ant_rx2 ? 1 : 0; - vctxrx_v2_rxing = rx_ant_rx2 ? 0 : 1; - vctxrx_v1_txing = 1; - vctxrx_v2_txing = 0; - } else { - vctxrx_v1_rxing = rx_ant_rx2 ? 1 : 0; - vctxrx_v2_rxing = rx_ant_rx2 ? 0 : 1; - vctxrx_v1_txing = 1; - vctxrx_v2_txing = 1; - } - - //swapped for routing reasons, reswap it here - if (instance == 1) { - std::swap(vctxrx_v1_rxing, vctxrx_v2_rxing); - std::swap(vctxrx_v1_txing, vctxrx_v2_txing); - } - - uint32_t tx_enable_a = (!tx_low_band) ? 1 : 0; - uint32_t tx_enable_b = (tx_low_band) ? 1 : 0; - - /* Set RX / TX band selects */ - uint32_t rx_band_select_a = 0; - uint32_t rx_band_select_b = 0; - uint32_t rx_band_select_c = 0; - uint32_t tx_band_select = 0; - - if (instance == 0) { - // RX - if (rx_freq < 450e6) { - rx_band_select_a = 5; // 3'b101 - rx_band_select_b = 0; // 2'bXX -- Don't care - rx_band_select_c = 1; // 2'b01 - } else if (rx_freq < 700e6) { - rx_band_select_a = 3; // 3'b011 - rx_band_select_b = 0; // 2'bXX -- Don't care - rx_band_select_c = 3; // 2'b11 - } else if (rx_freq < 1200e6) { - rx_band_select_a = 1; // 3'b001 - rx_band_select_b = 0; // 2'bXX -- Don't care - rx_band_select_c = 2; // 2'b10 - } else if (rx_freq < 1800e6) { - rx_band_select_a = 0; // 3'b000 - rx_band_select_b = 1; // 2'b01 - rx_band_select_c = 0; // 2'bXX -- Don't care - } else if (rx_freq < 2350e6){ - rx_band_select_a = 2; // 3'b010 - rx_band_select_b = 3; // 2'b11 - rx_band_select_c = 0; // 2'bXX -- Don't care - } else if (rx_freq < 2600e6){ - rx_band_select_a = 4; // 3'b100 - rx_band_select_b = 2; // 2'b10 - rx_band_select_c = 0; // 2'bXX -- Don't care - } else { // >= 2600e6 - rx_band_select_a = 5; // 3'bXX -- Don't care - rx_band_select_b = 0; // 2'bXX -- Don't care - rx_band_select_c = 1; // 2'bXX -- Don't care - } - } else if (instance == 1) { - if (rx_freq < 450e6) { - rx_band_select_a = 4; // 3'b100 - rx_band_select_b = 0; // 2'bXX -- Don't care - rx_band_select_c = 2; // 2'b10 - } else if (rx_freq < 700e6) { - rx_band_select_a = 2; // 3'b010 - rx_band_select_b = 0; // 2'bXX -- Don't care - rx_band_select_c = 3; // 2'b11 - } else if (rx_freq < 1200e6) { - rx_band_select_a = 0; // 3'b000 - rx_band_select_b = 0; // 2'bXX -- Don't care - rx_band_select_c = 1; // 2'b01 - } else if (rx_freq < 1800e6) { - rx_band_select_a = 1; // 3'b001 - rx_band_select_b = 2; // 2'b10 - rx_band_select_c = 0; // 2'bXX -- Don't care - } else if (rx_freq < 2350e6){ - rx_band_select_a = 3; // 3'b011 - rx_band_select_b = 3; // 2'b11 - rx_band_select_c = 0; // 2'bXX -- Don't care - } else if (rx_freq < 2600e6){ - rx_band_select_a = 5; // 3'b101 - rx_band_select_b = 1; // 2'b01 - rx_band_select_c = 0; // 2'bXX -- Don't care - } else { // >= 2600e6 - rx_band_select_a = 5; // 3'bXX -- Don't care - rx_band_select_b = 0; // 2'bXX -- Don't care - rx_band_select_c = 1; // 2'bXX -- Don't care - } - } else { - UHD_THROW_INVALID_CODE_PATH(); - } - - // TX band selects are the same for both radio frontends - if (tx_freq < 117.7e6) - tx_band_select = 7; // 3'b111 - else if (tx_freq < 178.2e6) - tx_band_select = 6; // 3'b110 - else if (tx_freq < 284.3e6) - tx_band_select = 5; // 3'b101 - else if (tx_freq < 453.7e6) - tx_band_select = 4; // 3'b100 - else if (tx_freq < 723.8e6) - tx_band_select = 3; // 3'b011 - else if (tx_freq < 1154.9e6) - tx_band_select = 2; // 3'b010 - else if (tx_freq < 1842.6e6) - tx_band_select = 1; // 3'b001 - else if (tx_freq < 2940.0e6) - tx_band_select = 0; // 3'b000 - else // > 2940.0e6 - tx_band_select = 7; // 3'bXXX -- Don't care, set to lowest band - - const uint32_t rx_selects = 0 - | (vcrx_v1_rxing << VCRX_V1) - | (vcrx_v2_rxing << VCRX_V2) - | (vctxrx_v1_rxing << VCTXRX_V1) - | (vctxrx_v2_rxing << VCTXRX_V2) - ; - const uint32_t tx_selects = 0 - | (vcrx_v1_txing << VCRX_V1) - | (vcrx_v2_txing << VCRX_V2) - | (vctxrx_v1_txing << VCTXRX_V1) - | (vctxrx_v2_txing << VCTXRX_V2) - ; - const uint32_t tx_enables = 0 - | (tx_enable_a << TX_ENABLEA) - | (tx_enable_b << TX_ENABLEB) - ; - const uint32_t rxtx_band_selects = 0 - | (rx_band_select_a << RX_BANDSEL) - | (rx_band_select_b << RXB_BANDSEL) - | (rx_band_select_c << RXC_BANDSEL) - | (tx_band_select << TX_BANDSEL) - ; - - // Form register values; - uint32_t oo_reg = rx_selects | rxtx_band_selects; - uint32_t rx_reg = rx_selects | rxtx_band_selects; - uint32_t tx_reg = tx_selects | tx_enables | rxtx_band_selects; - uint32_t fd_reg = tx_selects | tx_enables | rxtx_band_selects; //tx selects dominate in fd mode - - //add tx enables based on fe enable - tx_reg |= tx_enables; - fd_reg |= tx_enables; - - usrp::gpio_atr::gpio_atr_3000::sptr atr = _e3xx_perifs[instance].atr; - atr->set_atr_reg(usrp::gpio_atr::ATR_REG_IDLE, oo_reg); - atr->set_atr_reg(usrp::gpio_atr::ATR_REG_RX_ONLY, rx_reg); - atr->set_atr_reg(usrp::gpio_atr::ATR_REG_TX_ONLY, tx_reg); - atr->set_atr_reg(usrp::gpio_atr::ATR_REG_FULL_DUPLEX, fd_reg); - } -} - -void e3xx_radio_ctrl_impl::_update_atr_leds(usrp::gpio_atr::gpio_atr_3000::sptr leds, const std::string &rx_ant) -{ - const bool is_txrx = (rx_ant == "TX/RX"); - const int rx_led = (1 << 2); - const int tx_led = (1 << 1); - const int txrx_led = (1 << 0); - using namespace uhd::usrp::gpio_atr; - leds->set_atr_reg(ATR_REG_IDLE, 0); - leds->set_atr_reg(ATR_REG_RX_ONLY, is_txrx ? txrx_led : rx_led); - leds->set_atr_reg(ATR_REG_TX_ONLY, tx_led); - leds->set_atr_reg(ATR_REG_FULL_DUPLEX, rx_led | tx_led); -} - -void e3xx_radio_ctrl_impl::_update_gpio_state(void) -{ - UHD_RFNOC_BLOCK_TRACE() << "e3xx_radio_ctrl_impl::_update_gpio_state() " << std::endl; - uint32_t misc_reg = 0 - | (_misc.pps_sel << gpio_t::PPS_SEL) - | (_misc.mimo << gpio_t::MIMO) - | (_misc.radio_rst << gpio_t::RADIO_RST); - _tree->access<uint32_t>("global_regs/misc").set(misc_reg); -} - -void e3xx_radio_ctrl_impl::_update_enables(void) -{ - std::lock_guard<std::mutex> lock(_mutex); - UHD_RFNOC_BLOCK_TRACE() << "e3xx_radio_ctrl_impl::_update_enables() " << std::endl; - if (not _codec_ctrl) { - UHD_LOGGER_WARNING("E300") << "Attempting to access CODEC controls before setting up the radios." << std::endl; - return; - } - - const size_t num_rx = _is_streamer_active(RX_DIRECTION, FE0) + _is_streamer_active(RX_DIRECTION, FE1); - const size_t num_tx = _is_streamer_active(TX_DIRECTION, FE0) + _is_streamer_active(TX_DIRECTION, FE1); - - const bool mimo = (num_rx == 2) or (num_tx == 2); - - // This currently doesn't work with GNU Radio, so leave it uncommented - //if ((num_tx + num_rx) == 3) - // throw uhd::runtime_error("e300: 2 RX 1 TX and 1 RX 2 TX configurations not possible"); - - //setup the active chains in the codec - if ((num_rx + num_tx) == 0) { - // Ensure at least one RX chain is enabled so AD9361 outputs a sample clock - _codec_ctrl->set_active_chains(false, false, true, false); - } else { - _codec_ctrl->set_active_chains( - _is_streamer_active(TX_DIRECTION, FE0), - _is_streamer_active(TX_DIRECTION, FE1), - _is_streamer_active(RX_DIRECTION, FE0), - _is_streamer_active(RX_DIRECTION, FE1) - ); - } - - // Set radio data direction register cleared due to reset - for (size_t instance = 0; instance < _get_num_radios(); instance++) - { - _e3xx_perifs[instance].atr->set_gpio_ddr(usrp::gpio_atr::DDR_OUTPUT, 0xFFFFFFFF); - } - - //figure out if mimo is enabled based on new state - _misc.mimo = (mimo) ? 1 : 0; - _update_gpio_state(); - - //atrs change based on enables - _update_atrs(); -} - -void e3xx_radio_ctrl_impl::_update_time_source(const std::string &source) -{ - std::lock_guard<std::mutex> lock(_mutex); - UHD_LOGGER_DEBUG("E300") << boost::format("Setting time source to %s") % source << std::endl; - if (source == "none" or source == "internal") { - _misc.pps_sel = global_regs::PPS_INT; -#ifdef E300_GPSD - } else if (source == "gpsdo") { - _misc.pps_sel = global_regs::PPS_GPS; -#endif - } else if (source == "external") { - _misc.pps_sel = global_regs::PPS_EXT; - } else { - throw uhd::key_error("update_time_source: unknown source: " + source); - } - _update_gpio_state(); -} - -uhd::sensor_value_t e3xx_radio_ctrl_impl::_get_fe_pll_lock(const bool is_tx) -{ - const uint32_t st = _tree->access<uint32_t>("global_regs/pll").get(); - const bool locked = is_tx ? ((st & 0x1) > 0) : ((st & 0x2) > 0); - return sensor_value_t("LO", locked, "locked", "unlocked"); -} - -/**************************************************************************** - * Register block - ***************************************************************************/ -UHD_RFNOC_BLOCK_REGISTER(e3xx_radio_ctrl, "E3XXRadio"); diff --git a/host/lib/usrp/e300/e3xx_radio_ctrl_impl.hpp b/host/lib/usrp/e300/e3xx_radio_ctrl_impl.hpp deleted file mode 100644 index 390b0929c..000000000 --- a/host/lib/usrp/e300/e3xx_radio_ctrl_impl.hpp +++ /dev/null @@ -1,149 +0,0 @@ -// -// Copyright 2015-2016 Ettus Research -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. -// - -#ifndef INCLUDED_LIBUHD_RFNOC_E3XX_RADIO_CTRL_IMPL_HPP -#define INCLUDED_LIBUHD_RFNOC_E3XX_RADIO_CTRL_IMPL_HPP - -#include "e300_global_regs.hpp" -#include <uhdlib/usrp/cores/spi_core_3000.hpp> -#include <uhdlib/usrp/common/ad9361_ctrl.hpp> -#include <uhdlib/usrp/common/ad936x_manager.hpp> -#include <uhdlib/rfnoc/radio_ctrl_impl.hpp> -#include <uhd/usrp/gpio_defs.hpp> - -namespace uhd { - namespace rfnoc { - -/*! \brief Provide access to an E3XX radio. - */ -class e3xx_radio_ctrl_impl : public radio_ctrl_impl -{ -public: - /************************************************************************ - * Structors - ***********************************************************************/ - UHD_RFNOC_RADIO_BLOCK_CONSTRUCTOR_DECL(e3xx_radio_ctrl) - virtual ~e3xx_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); - - double set_tx_frequency(const double freq, const size_t chan); - double set_rx_frequency(const double freq, 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 set_rx_bandwidth(const double bandwidth, const size_t chan); - - double get_tx_gain(const size_t chan); - double get_rx_gain(const size_t chan); - double get_rx_bandwidth(const size_t chan); - - 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); - - size_t get_chan_from_dboard_fe(const std::string &fe, const direction_t); - std::string get_dboard_fe_from_chan(const size_t chan, const direction_t); - - /************************************************************************ - * RFIC setup and control - ***********************************************************************/ - /*! Set up the radio. No API calls may be made before this one. - */ - void setup_radio(uhd::usrp::ad9361_ctrl::sptr safe_codec_ctrl); - -private: - void _setup_radio_channel(const size_t chan); - void _reset_radio(void); - -protected: - /************************************************************************ - * Helpers - ***********************************************************************/ - virtual bool check_radio_config(); - void _enforce_tick_rate_limits(const size_t chans, const double tick_rate); - -private: - /************************************************************************ - * Peripheral controls - ***********************************************************************/ - void _update_fe_lo_freq(const std::string &fe, const double freq); - void _update_atrs(void); - void _update_atr_leds(uhd::usrp::gpio_atr::gpio_atr_3000::sptr leds, const std::string &rx_ant); - - void _update_gpio_state(void); - void _update_enables(void); - - void _update_time_source(const std::string &source); - - // get frontend lock sensor - uhd::sensor_value_t _get_fe_pll_lock(const bool is_tx); - - /************************************************************************ - * Internal GPIO control - ***********************************************************************/ - struct gpio_t - { - gpio_t() : pps_sel(uhd::usrp::e300::global_regs::PPS_INT), - mimo(0), radio_rst(0), tx_bandsels(0), - rx_bandsel_a(0), rx_bandsel_b(0), rx_bandsel_c(0) - {} - - uint32_t pps_sel; - uint32_t mimo; - uint32_t radio_rst; - - uint32_t tx_bandsels; - uint32_t rx_bandsel_a; - uint32_t rx_bandsel_b; - uint32_t rx_bandsel_c; - - static const size_t PPS_SEL = 0; - static const size_t MIMO = 2; - static const size_t RADIO_RST = 3; - static const size_t TX_BANDSEL = 4; - static const size_t RX_BANDSELA = 7; - static const size_t RX_BANDSELB = 13; - static const size_t RX_BANDSELC = 17; - }; - uint8_t _get_internal_gpio(uhd::usrp::gpio_atr::gpio_atr_3000::sptr); - -private: // members - struct e3xx_perifs_t - { - usrp::gpio_atr::gpio_atr_3000::sptr atr; - uhd::usrp::gpio_atr::gpio_atr_3000::sptr leds; - }; - //! SPI to talk to the AD936x - spi_core_3000::sptr _spi; - //! One ATR per channel - std::map<size_t, e3xx_perifs_t> _e3xx_perifs; - //! AD936x controls - uhd::usrp::ad9361_ctrl::sptr _codec_ctrl; - uhd::usrp::ad936x_manager::sptr _codec_mgr; - gpio_t _misc; - -}; /* class radio_ctrl_impl */ - -}} /* namespace uhd::rfnoc */ - -#endif /* INCLUDED_LIBUHD_RFNOC_E3XX_RADIO_CTRL_IMPL_HPP */ |