aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/include/uhd/rfnoc/blocks/radio_e31x.xml (renamed from host/include/uhd/rfnoc/blocks/radio_e3xx.xml)6
-rw-r--r--host/include/uhd/rfnoc/blocks/radio_e320.xml (renamed from host/include/uhd/rfnoc/blocks/radio_neon.xml)0
-rw-r--r--host/lib/CMakeLists.txt2
-rw-r--r--host/lib/usrp/CMakeLists.txt1
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_device.cpp2
-rw-r--r--host/lib/usrp/common/ad9361_driver/ad9361_device.h2
-rw-r--r--host/lib/usrp/dboard/CMakeLists.txt11
-rw-r--r--host/lib/usrp/dboard/db_e3x0.cpp54
-rw-r--r--host/lib/usrp/dboard/e3xx/CMakeLists.txt31
-rw-r--r--host/lib/usrp/dboard/e3xx/e31x_radio_ctrl_impl.cpp302
-rw-r--r--host/lib/usrp/dboard/e3xx/e31x_radio_ctrl_impl.hpp144
-rw-r--r--host/lib/usrp/dboard/e3xx/e31x_regs.hpp26
-rw-r--r--host/lib/usrp/dboard/e3xx/e320_radio_ctrl_impl.cpp272
-rw-r--r--host/lib/usrp/dboard/e3xx/e320_radio_ctrl_impl.hpp134
-rw-r--r--host/lib/usrp/dboard/e3xx/e320_regs.hpp (renamed from host/lib/usrp/dboard/neon/neon_regs.hpp)6
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_ad9361_iface.cpp (renamed from host/lib/usrp/dboard/neon/neon_ad9361_iface.cpp)19
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_ad9361_iface.hpp28
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_bands.cpp (renamed from host/lib/usrp/dboard/neon/neon_bands.cpp)114
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_constants.hpp (renamed from host/lib/usrp/dboard/neon/neon_constants.hpp)34
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_impl.cpp343
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_impl.hpp (renamed from host/lib/usrp/dboard/neon/neon_radio_ctrl_impl.hpp)178
-rw-r--r--host/lib/usrp/dboard/e3xx/e3xx_radio_ctrl_init.cpp (renamed from host/lib/usrp/dboard/neon/neon_radio_ctrl_init.cpp)62
-rw-r--r--host/lib/usrp/dboard/neon/CMakeLists.txt15
-rw-r--r--host/lib/usrp/dboard/neon/neon_ad9361_iface.hpp25
-rw-r--r--host/lib/usrp/dboard/neon/neon_radio_ctrl_impl.cpp563
-rw-r--r--host/lib/usrp/e300/CMakeLists.txt51
-rw-r--r--host/lib/usrp/e300/e300_common.cpp98
-rw-r--r--host/lib/usrp/e300/e300_common.hpp21
-rw-r--r--host/lib/usrp/e300/e300_defaults.hpp74
-rw-r--r--host/lib/usrp/e300/e300_eeprom_manager.cpp241
-rw-r--r--host/lib/usrp/e300/e300_eeprom_manager.hpp122
-rw-r--r--host/lib/usrp/e300/e300_fifo_config.cpp437
-rw-r--r--host/lib/usrp/e300/e300_fifo_config.hpp42
-rw-r--r--host/lib/usrp/e300/e300_fpga_defs.hpp19
-rw-r--r--host/lib/usrp/e300/e300_global_regs.cpp121
-rw-r--r--host/lib/usrp/e300/e300_global_regs.hpp71
-rw-r--r--host/lib/usrp/e300/e300_i2c.cpp400
-rw-r--r--host/lib/usrp/e300/e300_i2c.hpp68
-rw-r--r--host/lib/usrp/e300/e300_impl.cpp749
-rw-r--r--host/lib/usrp/e300/e300_impl.hpp195
-rw-r--r--host/lib/usrp/e300/e300_io_impl.cpp29
-rw-r--r--host/lib/usrp/e300/e300_network.cpp655
-rw-r--r--host/lib/usrp/e300/e300_network.hpp33
-rw-r--r--host/lib/usrp/e300/e300_regs.hpp25
-rw-r--r--host/lib/usrp/e300/e300_remote_codec_ctrl.cpp285
-rw-r--r--host/lib/usrp/e300/e300_remote_codec_ctrl.hpp64
-rw-r--r--host/lib/usrp/e300/e300_sensor_manager.cpp207
-rw-r--r--host/lib/usrp/e300/e300_sensor_manager.hpp68
-rw-r--r--host/lib/usrp/e300/e300_spi.cpp119
-rw-r--r--host/lib/usrp/e300/e300_spi.hpp24
-rw-r--r--host/lib/usrp/e300/e300_sysfs_hooks.cpp114
-rw-r--r--host/lib/usrp/e300/e3xx_radio_ctrl_impl.cpp770
-rw-r--r--host/lib/usrp/e300/e3xx_radio_ctrl_impl.hpp149
-rw-r--r--host/utils/CMakeLists.txt7
-rw-r--r--images/image_package_mapping.py40
-rw-r--r--images/manifest.txt4
-rw-r--r--mpm/CMakeLists.txt5
-rw-r--r--mpm/include/mpm/CMakeLists.txt2
-rw-r--r--mpm/include/mpm/ad9361/CMakeLists.txt1
-rw-r--r--mpm/include/mpm/ad9361/ad9361_ctrl.hpp47
-rw-r--r--mpm/include/mpm/ad9361/e31x_defaults.hpp45
-rw-r--r--mpm/include/mpm/dboards/CMakeLists.txt5
-rw-r--r--mpm/include/mpm/dboards/e31x_db_manager.hpp43
-rw-r--r--mpm/lib/CMakeLists.txt2
-rw-r--r--mpm/lib/dboards/CMakeLists.txt4
-rw-r--r--mpm/lib/dboards/e31x_db_manager.cpp79
-rw-r--r--mpm/python/CMakeLists.txt2
-rw-r--r--mpm/python/pyusrp_periphs/e31x/pyusrp_periphs.cpp30
-rw-r--r--mpm/python/usrp_mpm/CMakeLists.txt1
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt1
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/__init__.py1
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/e31x_db.py212
-rw-r--r--mpm/python/usrp_mpm/dboard_manager/neon.py19
-rw-r--r--mpm/python/usrp_mpm/e31x_legacy_eeprom.py103
-rw-r--r--mpm/python/usrp_mpm/periph_manager/CMakeLists.txt2
-rw-r--r--mpm/python/usrp_mpm/periph_manager/base.py6
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e31x.py744
-rw-r--r--mpm/python/usrp_mpm/periph_manager/e31x_periphs.py297
-rw-r--r--mpm/python/usrp_mpm/rpc_server.py29
-rw-r--r--mpm/tools/CMakeLists.txt4
80 files changed, 3186 insertions, 6174 deletions
diff --git a/host/include/uhd/rfnoc/blocks/radio_e3xx.xml b/host/include/uhd/rfnoc/blocks/radio_e31x.xml
index aece593a5..0635e397c 100644
--- a/host/include/uhd/rfnoc/blocks/radio_e3xx.xml
+++ b/host/include/uhd/rfnoc/blocks/radio_e31x.xml
@@ -1,11 +1,11 @@
<!--This defines one NoC-Block.-->
<nocblock>
- <name>Radio (E3XX)</name>
+ <name>Radio (E31X)</name>
<blockname>Radio</blockname>
- <key>E3XXRadio</key>
+ <key>E31XRadio</key>
<!--There can be several of these:-->
<ids>
- <id revision="0">12AD100000000000</id>
+ <id revision="0">12AD100000003310</id>
</ids>
<!-- Registers -->
<registers>
diff --git a/host/include/uhd/rfnoc/blocks/radio_neon.xml b/host/include/uhd/rfnoc/blocks/radio_e320.xml
index 01f286324..01f286324 100644
--- a/host/include/uhd/rfnoc/blocks/radio_neon.xml
+++ b/host/include/uhd/rfnoc/blocks/radio_e320.xml
diff --git a/host/lib/CMakeLists.txt b/host/lib/CMakeLists.txt
index 85e07c242..b171cbfef 100644
--- a/host/lib/CMakeLists.txt
+++ b/host/lib/CMakeLists.txt
@@ -69,7 +69,6 @@ LIBUHD_REGISTER_COMPONENT("GPSD" ENABLE_GPSD OFF "ENABLE_LIBUHD;ENABLE_GPSD;LIBG
# Devices
LIBUHD_REGISTER_COMPONENT("B100" ENABLE_B100 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF)
LIBUHD_REGISTER_COMPONENT("B200" ENABLE_B200 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF)
-LIBUHD_REGISTER_COMPONENT("E300" ENABLE_E300 OFF "ENABLE_LIBUHD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("USRP1" ENABLE_USRP1 ON "ENABLE_LIBUHD;ENABLE_USB" OFF OFF)
LIBUHD_REGISTER_COMPONENT("USRP2" ENABLE_USRP2 ON "ENABLE_LIBUHD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("X300" ENABLE_X300 ON "ENABLE_LIBUHD" OFF OFF)
@@ -78,6 +77,7 @@ LIBUHD_REGISTER_COMPONENT("MPMD" ENABLE_MPMD ON "ENABLE_LIBUHD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("N300" ENABLE_N300 ON "ENABLE_LIBUHD;ENABLE_MPMD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("N320" ENABLE_N320 ON "ENABLE_LIBUHD;ENABLE_MPMD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("E320" ENABLE_E320 ON "ENABLE_LIBUHD;ENABLE_MPMD" OFF OFF)
+LIBUHD_REGISTER_COMPONENT("E300" ENABLE_E300 ON "ENABLE_LIBUHD;ENABLE_MPMD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("OctoClock" ENABLE_OCTOCLOCK ON "ENABLE_LIBUHD" OFF OFF)
LIBUHD_REGISTER_COMPONENT("DPDK" ENABLE_DPDK ON "ENABLE_MPMD;DPDK_FOUND" OFF OFF)
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 &params)
- {
- 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 &params)
- {
- 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 &params,
- 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 &params) = 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 */
diff --git a/host/utils/CMakeLists.txt b/host/utils/CMakeLists.txt
index 4e8d8e5f0..58eb842e1 100644
--- a/host/utils/CMakeLists.txt
+++ b/host/utils/CMakeLists.txt
@@ -18,13 +18,6 @@ set(util_runtime_sources
uhd_cal_tx_iq_balance.cpp
)
-find_package(UDev)
-if(ENABLE_E300 AND NOT E300_FORCE_NETWORK)
- if(UDEV_FOUND)
- list(APPEND util_runtime_sources usrp_e3x0_network_mode.cpp)
- endif(UDEV_FOUND)
-endif(ENABLE_E300 AND NOT E300_FORCE_NETWORK)
-
#for each source: build an executable and install
foreach(util_source ${util_runtime_sources})
get_filename_component(util_name ${util_source} NAME_WE)
diff --git a/images/image_package_mapping.py b/images/image_package_mapping.py
index 95a251dbc..da76dc989 100644
--- a/images/image_package_mapping.py
+++ b/images/image_package_mapping.py
@@ -8,21 +8,33 @@
Container for the list of image package targets, and the information about them
"""
PACKAGE_MAPPING = {
- "e310": {
+ "e310_sg1": {
"type": "e3xx",
- "package_name": "e3xx_e310_fpga_default-g{}.zip",
- "files": ["usrp_e310_fpga.bin",
- "usrp_e310_fpga_sg3.bin",
- "usrp_e3xx_fpga_idle.bin",
- "usrp_e3xx_fpga_idle_sg3.bin",
- "usrp_e310_fpga.bit",
- "usrp_e310_fpga_sg3.bit",
- "usrp_e3xx_fpga_idle.bit",
- "usrp_e3xx_fpga_idle_sg3.bit",
- "usrp_e310_fpga.rpt",
- "usrp_e310_fpga_sg3.rpt",
- "usrp_e3xx_fpga_idle.rpt",
- "usrp_e3xx_fpga_idle_sg3.rpt"]
+ "package_name": "e3xx_e310_sg1_fpga_default-g{}.zip",
+ "files": ['usrp_e310_sg1_fpga.bit',
+ 'usrp_e310_sg1_fpga.bit.md5',
+ 'usrp_e310_sg1_fpga.dts',
+ 'usrp_e310_sg1_fpga.dts.md5',
+ 'usrp_e310_sg1_fpga.rpt',
+ 'usrp_e310_sg1_idle_fpga.bit',
+ 'usrp_e310_sg1_idle_fpga.bit.md5',
+ 'usrp_e310_sg1_idle_fpga.dts',
+ 'usrp_e310_sg1_idle_fpga.dts.md5',
+ 'usrp_e310_sg1_idle_fpga.rpt']
+ },
+ "e310_sg3": {
+ "type": "e3xx",
+ "package_name": "e3xx_e310_sg3_fpga_default-g{}.zip",
+ "files": ['usrp_e310_sg3_fpga.bit',
+ 'usrp_e310_sg3_fpga.bit.md5',
+ 'usrp_e310_sg3_fpga.dts',
+ 'usrp_e310_sg3_fpga.dts.md5',
+ 'usrp_e310_sg3_fpga.rpt',
+ 'usrp_e310_sg3_idle_fpga.bit',
+ 'usrp_e310_sg3_idle_fpga.bit.md5',
+ 'usrp_e310_sg3_idle_fpga.dts',
+ 'usrp_e310_sg3_idle_fpga.dts.md5',
+ 'usrp_e310_sg3_idle_fpga.rpt']
},
"e320": {
"type": "e3xx",
diff --git a/images/manifest.txt b/images/manifest.txt
index fcf874362..7b5acf6c8 100644
--- a/images/manifest.txt
+++ b/images/manifest.txt
@@ -8,8 +8,8 @@ x3xx_x300_fpga_default fpga-4bc2c6f x3xx/fpga-4bc2c6f/x3xx_x300_f
#dboard_ubx_cpld_default example_target
# E-Series
-e3xx_e310_fpga_default fpga-4bc2c6f e3xx/fpga-4bc2c6f/e3xx_e310_fpga_default-g4bc2c6f.zip be090f7cd187eb020e0cc8a8a7094b9691c4b7fa3dde82ca242030287a577475
-e3xx_e310_fpga_rfnoc fpga-d6a878b e3xx/fpga-d6a878b/e3xx_e310_fpga_rfnoc-gd6a878b.zip 5c9b89fb6293423644868c22e914de386a9af39ff031da6800a1cf39a90ea73b
+e3xx_e310_sg1_fpga_default fpga-f52a643 e3xx/fpga-f52a643/e3xx_e310_sg1_fpga_default-gf52a643.zip 03450918a7c312d53926f3318ea91a57162c545ada4058b9e83a4e0efd4755a4
+e3xx_e310_sg3_fpga_default fpga-f52a643 e3xx/fpga-f52a643/e3xx_e310_sg3_fpga_default-gf52a643.zip e8264dd48c3c3f6e65c8e5ef34a3629aa79a3f17ba845659e553bdcf3dfac303
e3xx_e320_fpga_default fpga-4bc2c6f e3xx/fpga-4bc2c6f/e3xx_e320_fpga_default-g4bc2c6f.zip 0def19fda1041866273c09d3bacc7e2dba916b8848c8a17a85fecd04009bab73
# E320 Filesystems, etc
e3xx_e320_sdk_default meta-ettus-v3.14.0.0-rc1 e3xx/meta-ettus-v3.14.0.0-rc1/e3xx_e320_sdk_default-v3.14.0.0-rc1.zip 0
diff --git a/mpm/CMakeLists.txt b/mpm/CMakeLists.txt
index 4f6c3b651..78759cc0b 100644
--- a/mpm/CMakeLists.txt
+++ b/mpm/CMakeLists.txt
@@ -123,7 +123,7 @@ if(_has_no_psabi)
message(STATUS "Disabling psABI warnings.")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-psabi")
endif(_has_no_psabi)
-set(MPM_ALL_DEVICES n3xx e320 tests)
+set(MPM_ALL_DEVICES n3xx e320 e31x tests)
set(MPM_DEVICE "n3xx" CACHE STRING "Choose an MPM device to build")
set_property(CACHE MPM_DEVICE PROPERTY STRINGS ${MPM_ALL_DEVICES})
# Validate MPM_DEVICE
@@ -139,12 +139,15 @@ if(MPM_DEVICE STREQUAL "n3xx")
set(ENABLE_MAGNESIUM ON)
elseif(MPM_DEVICE STREQUAL "e320")
set(ENABLE_E320 ON)
+elseif(MPM_DEVICE STREQUAL "e31x")
+ set(ENABLE_E300 ON)
endif()
MPM_REGISTER_COMPONENT("LibMPM" ENABLE_LIBMPM ON "Boost_FOUND" OFF ON)
MPM_REGISTER_COMPONENT("Mykonos" ENABLE_MYKONOS ON "ENABLE_LIBMPM" OFF OFF)
MPM_REGISTER_COMPONENT("Magnesium" ENABLE_MAGNESIUM ON "ENABLE_MYKONOS" OFF OFF)
MPM_REGISTER_COMPONENT("E320" ENABLE_E320 ON "ENABLE_LIBMPM" OFF OFF)
+MPM_REGISTER_COMPONENT("E300" ENABLE_E300 ON "ENABLE_LIBMPM" OFF OFF)
add_subdirectory(include)
include_directories(
diff --git a/mpm/include/mpm/CMakeLists.txt b/mpm/include/mpm/CMakeLists.txt
index e5b7193c6..f3637c913 100644
--- a/mpm/include/mpm/CMakeLists.txt
+++ b/mpm/include/mpm/CMakeLists.txt
@@ -11,7 +11,7 @@ install(FILES
if(ENABLE_MYKONOS)
add_subdirectory(ad937x)
-elseif(ENABLE_E320)
+elseif(ENABLE_E320 OR ENABLE_E300)
add_subdirectory(ad9361)
endif(ENABLE_MYKONOS)
diff --git a/mpm/include/mpm/ad9361/CMakeLists.txt b/mpm/include/mpm/ad9361/CMakeLists.txt
index 94ea655a7..2b2ea03ec 100644
--- a/mpm/include/mpm/ad9361/CMakeLists.txt
+++ b/mpm/include/mpm/ad9361/CMakeLists.txt
@@ -8,5 +8,6 @@
install(FILES
ad9361_ctrl.hpp
e320_defaults.hpp
+ e31x_defaults.hpp
DESTINATION ${INCLUDE_DIR}/mpm/catalina
)
diff --git a/mpm/include/mpm/ad9361/ad9361_ctrl.hpp b/mpm/include/mpm/ad9361/ad9361_ctrl.hpp
index 7673d7460..2405317fd 100644
--- a/mpm/include/mpm/ad9361/ad9361_ctrl.hpp
+++ b/mpm/include/mpm/ad9361/ad9361_ctrl.hpp
@@ -14,11 +14,16 @@
#include <functional>
#include <string>
#include <vector>
+#include <future>
namespace mpm { namespace chips {
using uhd::usrp::ad9361_ctrl;
}}; // namespace mpm::chips
+//! Async calls
+std::future<double> handle_tune;
+std::future<double> handle_set_clock_rate;
+
// TODO: pull in filter_info_base
#ifdef LIBMPM_PYTHON
void export_catalina(py::module& top_module)
@@ -58,6 +63,48 @@ void export_catalina(py::module& top_module)
.def("_get_filter", &ad9361_ctrl::get_filter)
.def("set_filter", &ad9361_ctrl::set_filter)
.def("output_digital_test_tone", &ad9361_ctrl::output_digital_test_tone);
+
+ m.def("async__tune", +[](
+ ad9361_ctrl& catalina,
+ const std::string &which,
+ const double value
+ ){
+ handle_tune = std::async(std::launch::async,
+ &ad9361_ctrl::tune,
+ &catalina,
+ which,
+ value
+ );
+ });
+ m.def("await__tune", +[](
+ )->bool{
+ if (handle_tune.wait_for(std::chrono::seconds(0))
+ == std::future_status::ready){
+ handle_tune.get();
+ return true;
+ }
+ return false;
+ });
+ m.def("async__set_clock_rate", +[](
+ ad9361_ctrl& catalina,
+ const double value
+ ){
+ handle_set_clock_rate = std::async(std::launch::async,
+ &ad9361_ctrl::set_clock_rate,
+ &catalina,
+ value
+ );
+ });
+ m.def("await__set_clock_rate", +[](
+ )->bool{
+ if (handle_set_clock_rate.wait_for(std::chrono::seconds(0))
+ == std::future_status::ready){
+ handle_set_clock_rate.get();
+ return true;
+ }
+ return false;
+ });
+
}
#endif
diff --git a/mpm/include/mpm/ad9361/e31x_defaults.hpp b/mpm/include/mpm/ad9361/e31x_defaults.hpp
new file mode 100644
index 000000000..c2188af8b
--- /dev/null
+++ b/mpm/include/mpm/ad9361/e31x_defaults.hpp
@@ -0,0 +1,45 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#ifndef INCLUDED_E31X_DEFAULTS_HPP
+#define INCLUDED_E31X_DEFAULTS_HPP
+
+#include "ad9361_ctrl.hpp"
+
+namespace mpm { namespace types { namespace e31x {
+
+using namespace uhd::usrp;
+
+class e31x_ad9361_client_t : public uhd::usrp::ad9361_params {
+public:
+ ~e31x_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_E31X_DEFAULTS_HPP
diff --git a/mpm/include/mpm/dboards/CMakeLists.txt b/mpm/include/mpm/dboards/CMakeLists.txt
index 03a5404bc..d1dd569d7 100644
--- a/mpm/include/mpm/dboards/CMakeLists.txt
+++ b/mpm/include/mpm/dboards/CMakeLists.txt
@@ -13,4 +13,9 @@ elseif(ENABLE_E320)
neon_manager.hpp
DESTINATION ${INCLUDE_DIR}/mpm/dboards
)
+elseif(ENABLE_E300)
+ install(FILES
+ e31x_db_manager.hpp
+ DESTINATION ${INCLUDE_DIR}/mpm/dboards
+ )
endif(ENABLE_MAGNESIUM)
diff --git a/mpm/include/mpm/dboards/e31x_db_manager.hpp b/mpm/include/mpm/dboards/e31x_db_manager.hpp
new file mode 100644
index 000000000..8777778e9
--- /dev/null
+++ b/mpm/include/mpm/dboards/e31x_db_manager.hpp
@@ -0,0 +1,43 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#pragma once
+
+#include <mpm/ad9361/ad9361_ctrl.hpp>
+#include <mpm/types/lockable.hpp>
+#include <mpm/types/regs_iface.hpp>
+#include <boost/shared_ptr.hpp>
+#include <memory>
+#include <mutex>
+
+namespace mpm { namespace dboards {
+ class e31x_db_manager
+ {
+ public:
+ e31x_db_manager(const std::string &catalina_spidev);
+
+ /*! Return a reference to the radio chip controls
+ */
+ mpm::chips::ad9361_ctrl::sptr get_radio_ctrl(){ return _catalina_ctrl; }
+
+ private:
+ mpm::chips::ad9361_ctrl::sptr _catalina_ctrl;
+ };
+
+}}; /* namespace mpm::dboards */
+
+#ifdef LIBMPM_PYTHON
+void export_e31x_db(py::module& top_module)
+{
+ using namespace mpm::dboards;
+ auto m = top_module.def_submodule("dboards");
+
+ py::class_<mpm::dboards::e31x_db_manager>(m, "e31x_db_manager")
+ .def(py::init<std::string>())
+ .def("get_radio_ctrl", &mpm::dboards::e31x_db_manager::get_radio_ctrl);
+}
+#endif
diff --git a/mpm/lib/CMakeLists.txt b/mpm/lib/CMakeLists.txt
index 10f8f0d9d..82a5d8e16 100644
--- a/mpm/lib/CMakeLists.txt
+++ b/mpm/lib/CMakeLists.txt
@@ -14,7 +14,7 @@ add_subdirectory(types)
if(ENABLE_MYKONOS)
add_subdirectory(mykonos)
-elseif(ENABLE_E320)
+elseif(ENABLE_E320 OR ENABLE_E300)
add_subdirectory(catalina)
endif(ENABLE_MYKONOS)
diff --git a/mpm/lib/dboards/CMakeLists.txt b/mpm/lib/dboards/CMakeLists.txt
index 0760d9fd1..4a13528eb 100644
--- a/mpm/lib/dboards/CMakeLists.txt
+++ b/mpm/lib/dboards/CMakeLists.txt
@@ -16,4 +16,8 @@ elseif(ENABLE_E320)
USRP_PERIPHS_ADD_OBJECT(dboards
neon_manager.cpp
)
+elseif(ENABLE_E300)
+ USRP_PERIPHS_ADD_OBJECT(dboards
+ e31x_db_manager.cpp
+ )
endif(ENABLE_MAGNESIUM)
diff --git a/mpm/lib/dboards/e31x_db_manager.cpp b/mpm/lib/dboards/e31x_db_manager.cpp
new file mode 100644
index 000000000..b433dde30
--- /dev/null
+++ b/mpm/lib/dboards/e31x_db_manager.cpp
@@ -0,0 +1,79 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <mpm/ad9361/e31x_defaults.hpp>
+#include <mpm/dboards/e31x_db_manager.hpp>
+#include <mpm/spi/spi_iface.hpp>
+#include <mpm/spi/spi_regs_iface.hpp>
+#include <mpm/types/regs_iface.hpp>
+#include <boost/make_shared.hpp>
+#include <memory>
+
+using namespace mpm::dboards;
+using namespace mpm::chips;
+using namespace mpm::types;
+using namespace mpm::types::e31x;
+
+namespace { /*anon*/
+
+constexpr uint32_t AD9361_SPI_WRITE_CMD = 0x00800000;
+constexpr uint32_t AD9361_SPI_READ_CMD = 0x00000000;
+constexpr uint32_t AD9361_SPI_ADDR_MASK = 0x003FFF00;
+constexpr uint32_t AD9361_SPI_ADDR_SHIFT = 8;
+constexpr uint32_t AD9361_SPI_DATA_MASK = 0x000000FF;
+constexpr uint32_t AD9361_SPI_DATA_SHIFT = 0;
+constexpr uint32_t AD9361_SPI_NUM_BITS = 24;
+constexpr uint32_t AD9361_SPI_SPEED_HZ = 2000000;
+constexpr int AD9361_SPI_MODE = 1;
+
+} // namespace /*anon*/
+
+/*! MPM-style E310 SPI Iface for AD9361 CTRL
+ *
+ */
+class e310_ad9361_io_spi : public ad9361_io
+{
+public:
+ e310_ad9361_io_spi(regs_iface::sptr regs_iface, uint32_t slave_num) :
+ _regs_iface(regs_iface), _slave_num(slave_num) { }
+
+ ~e310_ad9361_io_spi() {/*nop*/}
+
+ uint8_t peek8(uint32_t reg)
+ {
+ return _regs_iface->peek8(reg);
+ }
+
+ void poke8(uint32_t reg, uint8_t val)
+ {
+ _regs_iface->poke8(reg, val);
+ }
+
+private:
+ regs_iface::sptr _regs_iface;
+ uint32_t _slave_num;
+};
+
+e31x_db_manager::e31x_db_manager(const std::string &catalina_spidev)
+{
+ // Make the MPM-style low level SPI Regs iface
+ auto spi_iface = mpm::spi::make_spi_regs_iface(
+ mpm::spi::spi_iface::make_spidev(catalina_spidev, AD9361_SPI_SPEED_HZ, AD9361_SPI_MODE),
+ AD9361_SPI_ADDR_SHIFT,
+ AD9361_SPI_DATA_SHIFT,
+ AD9361_SPI_READ_CMD,
+ AD9361_SPI_WRITE_CMD);
+ // Make the SPI interface
+ auto spi_io_iface = std::make_shared<e310_ad9361_io_spi>(spi_iface, 0);
+ // Translate from a std shared_ptr to Boost (for legacy compatability)
+ auto spi_io_iface_boost = boost::shared_ptr<e310_ad9361_io_spi>(
+ spi_io_iface.get(),
+ [spi_io_iface](...) mutable { spi_io_iface.reset(); });
+ // Make the actual Catalina Ctrl object
+ _catalina_ctrl = ad9361_ctrl::make_spi(
+ boost::make_shared<e31x_ad9361_client_t>(),
+ spi_io_iface_boost);
+}
diff --git a/mpm/python/CMakeLists.txt b/mpm/python/CMakeLists.txt
index c78dc60b1..3a5b30d4e 100644
--- a/mpm/python/CMakeLists.txt
+++ b/mpm/python/CMakeLists.txt
@@ -12,6 +12,8 @@ if(MPM_DEVICE STREQUAL "n3xx")
add_library(pyusrp_periphs SHARED pyusrp_periphs/n3xx/pyusrp_periphs.cpp)
elseif(MPM_DEVICE STREQUAL "e320")
add_library(pyusrp_periphs SHARED pyusrp_periphs/e320/pyusrp_periphs.cpp)
+elseif(MPM_DEVICE STREQUAL "e31x")
+ add_library(pyusrp_periphs SHARED pyusrp_periphs/e31x/pyusrp_periphs.cpp)
endif(MPM_DEVICE STREQUAL "n3xx")
target_include_directories(pyusrp_periphs PUBLIC
diff --git a/mpm/python/pyusrp_periphs/e31x/pyusrp_periphs.cpp b/mpm/python/pyusrp_periphs/e31x/pyusrp_periphs.cpp
new file mode 100644
index 000000000..b7971407c
--- /dev/null
+++ b/mpm/python/pyusrp_periphs/e31x/pyusrp_periphs.cpp
@@ -0,0 +1,30 @@
+//
+// Copyright 2018 Ettus Research, a National Instruments Company
+// Copyright 2019 Ettus Research, a National Instruments Brand
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+//
+
+#include <pybind11/pybind11.h>
+namespace py = pybind11;
+#define LIBMPM_PYTHON
+
+// Allow boost::shared_ptr<T> to be a holder class of an object (PyBind11
+// supports std::shared_ptr and std::unique_ptr out of the box)
+#include <boost/shared_ptr.hpp>
+PYBIND11_DECLARE_HOLDER_TYPE(T, boost::shared_ptr<T>);
+
+#include <mpm/ad9361/ad9361_ctrl.hpp>
+#include <mpm/dboards/e31x_db_manager.hpp>
+#include <mpm/spi/spi_python.hpp>
+#include <mpm/types/types_python.hpp>
+#include <mpm/xbar_iface.hpp>
+
+PYBIND11_MODULE(libpyusrp_periphs, m)
+{
+ export_types(m);
+ export_spi(m);
+ export_xbar(m);
+ export_catalina(m);
+ export_e31x_db(m);
+}
diff --git a/mpm/python/usrp_mpm/CMakeLists.txt b/mpm/python/usrp_mpm/CMakeLists.txt
index 1b85c8561..6b6d99a30 100644
--- a/mpm/python/usrp_mpm/CMakeLists.txt
+++ b/mpm/python/usrp_mpm/CMakeLists.txt
@@ -15,6 +15,7 @@ set(USRP_MPM_TOP_FILES
${CMAKE_CURRENT_SOURCE_DIR}/components.py
${CMAKE_CURRENT_SOURCE_DIR}/discovery.py
${CMAKE_CURRENT_SOURCE_DIR}/eeprom.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/e31x_legacy_eeprom.py
${CMAKE_CURRENT_SOURCE_DIR}/ethtable.py
${CMAKE_CURRENT_SOURCE_DIR}/gpsd_iface.py
${CMAKE_CURRENT_SOURCE_DIR}/liberiotable.py
diff --git a/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt b/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt
index 650a21aab..3e4f6ba76 100644
--- a/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt
+++ b/mpm/python/usrp_mpm/dboard_manager/CMakeLists.txt
@@ -19,6 +19,7 @@ set(USRP_MPM_DBMGR_FILES
${CMAKE_CURRENT_SOURCE_DIR}/dac_rh.py
${CMAKE_CURRENT_SOURCE_DIR}/eiscat.py
${CMAKE_CURRENT_SOURCE_DIR}/neon.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/e31x_db.py
${CMAKE_CURRENT_SOURCE_DIR}/gain_rh.py
${CMAKE_CURRENT_SOURCE_DIR}/gaintables_rh.py
${CMAKE_CURRENT_SOURCE_DIR}/lmk_eiscat.py
diff --git a/mpm/python/usrp_mpm/dboard_manager/__init__.py b/mpm/python/usrp_mpm/dboard_manager/__init__.py
index 70e7881db..77fd84436 100644
--- a/mpm/python/usrp_mpm/dboard_manager/__init__.py
+++ b/mpm/python/usrp_mpm/dboard_manager/__init__.py
@@ -10,6 +10,7 @@ from .base import DboardManagerBase
from .magnesium import Magnesium
from .rhodium import Rhodium
from .neon import Neon
+from .e31x_db import E31x_db
from .eiscat import EISCAT
from .test import test
from .unknown import unknown
diff --git a/mpm/python/usrp_mpm/dboard_manager/e31x_db.py b/mpm/python/usrp_mpm/dboard_manager/e31x_db.py
new file mode 100644
index 000000000..358b69f88
--- /dev/null
+++ b/mpm/python/usrp_mpm/dboard_manager/e31x_db.py
@@ -0,0 +1,212 @@
+#
+# Copyright 2018 Ettus Research, a National Instruments Company
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+"""
+E310 dboard (RF and control) implementation module
+"""
+
+import threading
+import time
+from six import iterkeys, iteritems
+from usrp_mpm import lib # Pulls in everything from C++-land
+from usrp_mpm.bfrfs import BufferFS
+from usrp_mpm.dboard_manager import DboardManagerBase
+from usrp_mpm.mpmlog import get_logger
+from usrp_mpm.sys_utils.udev import get_eeprom_paths
+from usrp_mpm.sys_utils.uio import UIO
+from usrp_mpm.periph_manager.e31x_periphs import MboardRegsControl
+from usrp_mpm.mpmutils import async_exec
+
+###############################################################################
+# Main dboard control class
+###############################################################################
+class E31x_db(DboardManagerBase):
+ """
+ Holds all dboard specific information and methods of the E31x_db dboard
+ """
+ #########################################################################
+ # Overridables
+ #
+ # See DboardManagerBase for documentation on these fields
+ #########################################################################
+ pids = [0x0110]
+ rx_sensor_callback_map = {
+ 'ad9361_temperature': 'get_catalina_temp_sensor',
+ 'rssi' : 'get_rssi_sensor',
+ 'lo_lock' : 'get_lo_lock_sensor',
+ }
+ tx_sensor_callback_map = {
+ 'ad9361_temperature': 'get_catalina_temp_sensor',
+ }
+ # Maps the chipselects to the corresponding devices:
+ spi_chipselect = {"catalina": 0,
+ }
+
+ default_master_clock_rate = 16e6
+ MIN_MASTER_CLK_RATE = 220e3
+ MAX_MASTER_CLK_RATE = 61.44e6
+
+ def __init__(self, slot_idx, **kwargs):
+ super(E31x_db, self).__init__(slot_idx, **kwargs)
+ self.log = get_logger("E31x_db-{}".format(slot_idx))
+ self.log.trace("Initializing e31x daughterboard, slot index %d",
+ self.slot_idx)
+ self.rev = int(self.device_info['rev'])
+ self.log.trace("This is a rev: {}".format(chr(65 + self.rev)))
+ # These will get updated during init()
+ self.master_clock_rate = None
+ # Predeclare some attributes to make linter happy:
+ self.catalina = None
+ self.eeprom_fs = None
+ self.eeprom_path = None
+ # Now initialize all peripherals. If that doesn't work, put this class
+ # into a non-functional state (but don't crash, or we can't talk to it
+ # any more):
+ try:
+ self._init_periphs()
+ self._periphs_initialized = True
+ except Exception as ex:
+ self.log.error("Failed to initialize peripherals: %s",
+ str(ex))
+ self._periphs_initialized = False
+
+ def _init_periphs(self):
+ """
+ Initialize power and peripherals that don't need user-settings
+ """
+ self.log.debug("Loading C++ drivers...")
+ # Setup Catalina / the E31x_db Manager
+ self._device = lib.dboards.e31x_db_manager(
+ self._spi_nodes['catalina']
+ )
+ self.catalina = self._device.get_radio_ctrl()
+ self.log.trace("Loaded C++ drivers.")
+ self._init_cat_api(self.catalina)
+
+ def _init_cat_api(self, cat):
+ """
+ Propagate the C++ Catalina API into Python land.
+ """
+ def export_method(obj, method):
+ " Export a method object, including docstring "
+ meth_obj = getattr(obj, method)
+ def func(*args):
+ " Functor for storing docstring too "
+ return meth_obj(*args)
+ func.__doc__ = meth_obj.__doc__
+ return func
+ self.log.trace("Forwarding AD9361 methods to E31x_db class...")
+ for method in [
+ x for x in dir(self.catalina)
+ if not x.startswith("_") and \
+ callable(getattr(self.catalina, x))]:
+ self.log.trace("adding {}".format(method))
+ setattr(self, method, export_method(cat, method))
+
+ def init(self, args):
+ if not self._periphs_initialized:
+ error_msg = "Cannot run init(), peripherals are not initialized!"
+ self.log.error(error_msg)
+ raise RuntimeError(error_msg)
+ master_clock_rate = \
+ float(args.get('master_clock_rate',
+ self.default_master_clock_rate))
+ assert self.MIN_MASTER_CLK_RATE <= master_clock_rate <= self.MAX_MASTER_CLK_RATE, \
+ "Invalid master clock rate: {:.02f} MHz".format(
+ master_clock_rate / 1e6)
+ master_clock_rate_changed = master_clock_rate != self.master_clock_rate
+ if master_clock_rate_changed:
+ self.master_clock_rate = master_clock_rate
+ self.log.debug("Updating master clock rate to {:.02f} MHz!".format(
+ self.master_clock_rate / 1e6
+ ))
+ # Some default chains on -- needed for setup purposes
+ self.catalina.set_active_chains(True, False, True, False)
+ self.set_catalina_clock_rate(self.master_clock_rate)
+
+ return True
+
+ def get_master_clock_rate(self):
+ " Return master clock rate (== sampling rate) "
+ return self.master_clock_rate
+
+ ##########################################################################
+ # Sensors
+ ##########################################################################
+ def get_ad9361_lo_lock(self, which):
+ """
+ Return LO lock status (Boolean!) of AD9361. 'which' must be
+ either 'tx' or 'rx'
+ """
+ self.mboard_regs_label = "mboard-regs"
+ self.mboard_regs_control = MboardRegsControl(
+ self.mboard_regs_label, self.log)
+ if which == "tx":
+ locked = self. mboard_regs_control.get_ad9361_tx_lo_lock()
+ elif which == "rx":
+ locked = self. mboard_regs_control.get_ad9361_rx_lo_lock()
+ else:
+ locked = False
+ return locked
+
+ def get_lo_lock_sensor(self, which):
+ """
+ Get sensor dict with LO lock status
+ """
+ self.log.trace("Reading LO Lock.")
+ lo_locked = self.get_ad9361_lo_lock(which)
+ return {
+ 'name': 'ad9361_lock',
+ 'type': 'BOOLEAN',
+ 'unit': 'locked' if lo_locked else 'unlocked',
+ 'value': str(lo_locked).lower(),
+ }
+
+ def get_catalina_temp_sensor(self, _):
+ """
+ Get temperature sensor reading of Catalina.
+ """
+ # Note: the unused argument is channel
+ self.log.trace("Reading Catalina temperature.")
+ return {
+ 'name': 'ad9361_temperature',
+ 'type': 'REALNUM',
+ 'unit': 'C',
+ 'value': str(self.catalina.get_temperature())
+ }
+
+ def get_rssi_val(self, which):
+ """
+ Return the current RSSI of `which` chain in Catalina
+ """
+ return self.catalina.get_rssi(which)
+
+ def get_rssi_sensor(self, chan):
+ """
+ Return a sensor dictionary containing the current RSSI of `which` chain in Catalina
+ """
+ which = 'RX' + str(chan+1)
+ return {
+ 'name': 'rssi',
+ 'type': 'REALNUM',
+ 'unit': 'dB',
+ 'value': str(self.get_rssi_val(which)),
+ }
+
+ def set_catalina_clock_rate(self, rate):
+ """
+ Async call to catalina set_clock_rate
+ """
+ self.log.trace("Setting Clock rate to {}".format(rate))
+ async_exec(lib.ad9361, "set_clock_rate", self.catalina, rate)
+ return rate
+
+ def catalina_tune(self, which, freq):
+ """
+ Async call to catalina tune
+ """
+ self.log.trace("Tuning {} {}".format(which, freq))
+ async_exec(lib.ad9361, "tune", self.catalina, which, freq)
+ return self.catalina.get_freq(which)
diff --git a/mpm/python/usrp_mpm/dboard_manager/neon.py b/mpm/python/usrp_mpm/dboard_manager/neon.py
index c0eb10eae..00438503d 100644
--- a/mpm/python/usrp_mpm/dboard_manager/neon.py
+++ b/mpm/python/usrp_mpm/dboard_manager/neon.py
@@ -18,7 +18,7 @@ from usrp_mpm.mpmlog import get_logger
from usrp_mpm.sys_utils.udev import get_eeprom_paths
from usrp_mpm.sys_utils.uio import UIO
from usrp_mpm.periph_manager.e320_periphs import MboardRegsControl
-
+from usrp_mpm.mpmutils import async_exec
###############################################################################
# Main dboard control class
@@ -186,7 +186,7 @@ class Neon(DboardManagerBase):
))
# Some default chains on -- needed for setup purposes
self.catalina.set_active_chains(True, False, True, False)
- self.catalina.set_clock_rate(self.master_clock_rate)
+ self.set_catalina_clock_rate(self.master_clock_rate)
return True
@@ -321,3 +321,18 @@ class Neon(DboardManagerBase):
'value': str(self.get_rssi_val(which)),
}
+ def set_catalina_clock_rate(self, rate):
+ """
+ Async call to catalina set_clock_rate
+ """
+ self.log.trace("Setting Clock rate to {}".format(rate))
+ async_exec(lib.ad9361, "set_clock_rate", self.catalina, rate)
+ return rate
+
+ def catalina_tune(self, which, freq):
+ """
+ Async call to catalina tune
+ """
+ self.log.trace("Tuning {} {}".format(which, freq))
+ async_exec(lib.ad9361, "tune", self.catalina, which, freq)
+ return self.catalina.get_freq(which)
diff --git a/mpm/python/usrp_mpm/e31x_legacy_eeprom.py b/mpm/python/usrp_mpm/e31x_legacy_eeprom.py
new file mode 100644
index 000000000..4c0fb19a5
--- /dev/null
+++ b/mpm/python/usrp_mpm/e31x_legacy_eeprom.py
@@ -0,0 +1,103 @@
+#
+# Copyright 2017 Ettus Research, a National Instruments Company
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+"""
+EEPROM management code
+"""
+
+import struct
+import zlib
+from builtins import zip
+from builtins import object
+
+
+class MboardEEPROM(object):
+ """
+ Given a nvmem path, read out EEPROM values from the motherboard's EEPROM.
+ The format of data in the EEPROM must follow the following standard:
+
+ E310 Legacy EEPROM Format
+
+ - 2 bytes data_version_major
+ - 2 bytes data_version_minor
+ - 6 bytes MAC address
+ - 2 bytes hw_pid
+ - 2 bytes hw_rev
+ - 8 bytes serial number (zero-terminated string of 7 characters)
+ - 12 bytes padding
+ - 8 bytes user_name
+
+ MAC addresses are ignored here; they are read elsewhere. If we really need
+ to know the MAC address of an interface, we can fish it out the raw data,
+ or ask the system.
+ """
+
+ # Refer e300_eeprom_manager.hpp.
+ eeprom_header_format = "<H H 6s H H 7s 12s 8s"
+ eeprom_header_keys = ('data_version_major', 'data_version_minor', 'mac_address', 'pid', 'rev', 'serial', 'pad', 'user_name')
+
+class DboardEEPROM(object):
+ """
+ Given a nvmem path, read out EEPROM values from the daughterboard's EEPROM.
+ The format of data in the EEPROM must follow the following standard:
+
+ E310 Legacy EEPROM Format
+
+ - 2 bytes data_version_major
+ - 2 bytes data_version_minor
+ - 2 bytes hw_pid
+ - 2 bytes hw_rev
+ - 8 bytes serial number (zero-terminated string of 7 characters)
+ - 12 bytes padding
+ """
+
+ # Refer e300_eeprom_manager.hpp.
+ eeprom_header_format = "<H H H H 7s 12s"
+ eeprom_header_keys = ('data_version_major', 'data_version_minor', 'pid', 'rev', 'serial', 'pad')
+
+def read_eeprom(
+ isMotherboard,
+ nvmem_path,
+ offset,
+ eeprom_header_format,
+ eeprom_header_keys,
+ max_size=None,
+):
+ """
+ Read the EEPROM located at nvmem_path and return a tuple (header, data)
+ Header is already parsed in the common header fields
+ Data contains the full eeprom data structure
+
+ nvmem_path -- Path to readable file (typically something in sysfs)
+ eeprom_header_format -- List of header formats, by version
+ eeprom_header_keys -- List of keys for the entries in the EEPROM
+ max_size -- Max number of bytes to be read. If omitted, will read the full file.
+ """
+
+ max_size = max_size or -1
+ with open(nvmem_path, "rb") as nvmem_file:
+ data = nvmem_file.read(max_size)[offset:]
+ eeprom_parser = struct.Struct(eeprom_header_format)
+ eeprom_keys = eeprom_header_keys
+ parsed_data = eeprom_parser.unpack_from(data)
+
+ if isMotherboard: # E310 MB.
+ # Rectify the PID and REV parsing. Reverse the bytes.
+ # PID and REV are the 4th and 5th elements in the tuple.
+ parsed_data_list = list(parsed_data)
+ parsed_data_list[3] = struct.unpack("<H", struct.pack(">H", parsed_data_list[3]))[0]
+ parsed_data_list[4] = struct.unpack("<H", struct.pack(">H", parsed_data_list[4]))[0]
+ parsed_data = tuple(parsed_data_list)
+
+ else: # E310 DB.
+ # Rectify the PID and REV parsing. Reverse the bytes.
+ # PID and REV are the 3rd and 4th elements in the tuple.
+ parsed_data_list = list(parsed_data)
+ parsed_data_list[2] = struct.unpack("<H", struct.pack(">H", parsed_data_list[2]))[0]
+ parsed_data_list[3] = struct.unpack("<H", struct.pack(">H", parsed_data_list[3]))[0]
+ parsed_data = tuple(parsed_data_list)
+
+ ret_val = (dict(list(zip(eeprom_keys, parsed_data))),data)
+ return ret_val \ No newline at end of file
diff --git a/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt b/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt
index 994b1d64a..987bc184b 100644
--- a/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt
+++ b/mpm/python/usrp_mpm/periph_manager/CMakeLists.txt
@@ -15,6 +15,8 @@ set(USRP_MPM_PERIPHMGR_FILES
${CMAKE_CURRENT_SOURCE_DIR}/n3xx_periphs.py
${CMAKE_CURRENT_SOURCE_DIR}/e320.py
${CMAKE_CURRENT_SOURCE_DIR}/e320_periphs.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/e31x.py
+ ${CMAKE_CURRENT_SOURCE_DIR}/e31x_periphs.py
)
list(APPEND USRP_MPM_FILES ${USRP_MPM_PERIPHMGR_FILES})
set(USRP_MPM_FILES ${USRP_MPM_FILES} PARENT_SCOPE)
diff --git a/mpm/python/usrp_mpm/periph_manager/base.py b/mpm/python/usrp_mpm/periph_manager/base.py
index 2dc69e908..e297effbd 100644
--- a/mpm/python/usrp_mpm/periph_manager/base.py
+++ b/mpm/python/usrp_mpm/periph_manager/base.py
@@ -131,6 +131,12 @@ class PeriphManagerBase(object):
# specific implementation. Each PeriphManagerBase-derived class should list
# information required to update the component, like a callback function
updateable_components = {}
+ # The RPC server checks this value to determine if it needs to clear
+ # the RPC method registry. This is typically to remove stale references
+ # to RPC methods caused by removal of overlay on unclaim() by peripheral
+ # manager. Additionally the RPC server will re-register all methods on
+ # a claim(). Override and set to True in the derived class if desired.
+ clear_rpc_method_registry_on_unclaim = False
@staticmethod
def generate_device_info(eeprom_md, mboard_info, dboard_infos):
diff --git a/mpm/python/usrp_mpm/periph_manager/e31x.py b/mpm/python/usrp_mpm/periph_manager/e31x.py
new file mode 100644
index 000000000..722f8d7a9
--- /dev/null
+++ b/mpm/python/usrp_mpm/periph_manager/e31x.py
@@ -0,0 +1,744 @@
+#
+# Copyright 2018-2019 Ettus Research, a National Instruments Company
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+"""
+E310 implementation module
+"""
+
+from __future__ import print_function
+import bisect
+import copy
+import re
+import threading
+from six import iteritems, itervalues
+from usrp_mpm.components import ZynqComponents
+from usrp_mpm.dboard_manager import E31x_db
+from usrp_mpm.mpmtypes import SID
+from usrp_mpm.mpmutils import assert_compat_number, str2bool
+from usrp_mpm.periph_manager import PeriphManagerBase
+from usrp_mpm.rpc_server import no_rpc
+from usrp_mpm.sys_utils import dtoverlay
+from usrp_mpm.sys_utils.sysfs_thermal import read_sysfs_sensors_value
+from usrp_mpm.sys_utils.udev import get_spidev_nodes
+from usrp_mpm.xports import XportMgrLiberio
+from usrp_mpm.periph_manager.e31x_periphs import MboardRegsControl
+from usrp_mpm.sys_utils.udev import get_eeprom_paths
+from usrp_mpm import e31x_legacy_eeprom
+
+E310_DEFAULT_CLOCK_SOURCE = 'internal'
+E310_DEFAULT_TIME_SOURCE = 'internal'
+E310_DEFAULT_ENABLE_FPGPIO = True
+E310_FPGA_COMPAT = (1,0)
+E310_DBOARD_SLOT_IDX = 0
+
+###############################################################################
+# Transport managers
+###############################################################################
+
+class E310XportMgrLiberio(XportMgrLiberio):
+ " E310-specific Liberio configuration "
+ max_chan = 4
+ xbar_dev = "/dev/crossbar0"
+ xbar_port = 0
+
+###############################################################################
+# Main Class
+###############################################################################
+class e31x(ZynqComponents, PeriphManagerBase):
+ """
+ Holds E310 specific attributes and methods
+ """
+ #########################################################################
+ # Overridables
+ #
+ # See PeriphManagerBase for documentation on these fields
+ #########################################################################
+ description = "E300-Series Device"
+ # 0x77d2 and 0x77d3
+ pids = {0x77D2: 'e310_sg1', #sg1
+ 0x77D3: 'e310_sg3'} #sg3
+ mboard_eeprom_addr = "e0004000.i2c"
+ mboard_eeprom_offset = 0
+ mboard_eeprom_max_len = 64
+ # We have two nvem paths on the E310.
+ # This one ensures that we get the right path for the MB.
+ mboard_eeprom_path_index = 1
+ mboard_info = {"type": "e3xx"}
+ mboard_sensor_callback_map = {
+ 'ref_locked': 'get_ref_lock_sensor',
+ 'temp_fpga' : 'get_fpga_temp_sensor',
+ 'temp_mb' : 'get_mb_temp_sensor',
+ }
+ dboard_eeprom_addr = "e0004000.i2c"
+
+ # Actual DB EEPROM bytes are just 28. Reading just a couple more.
+ # Refer e300_eeprom_manager.hpp
+ dboard_eeprom_max_len = 32
+
+ max_num_dboards = 1
+
+ # We're on a Zynq target, so the following two come from the Zynq standard
+ # device tree overlay (tree/arch/arm/boot/dts/zynq-7000.dtsi)
+ dboard_spimaster_addrs = ["e0006000.spi"]
+ # E310-specific settings
+ # Label for the mboard UIO
+ mboard_regs_label = "mboard-regs"
+ # Override the list of updateable components
+ updateable_components = {
+ 'fpga': {
+ 'callback': "update_fpga",
+ 'path': '/lib/firmware/{}.bin',
+ 'reset': True,
+ },
+ 'dts': {
+ 'callback': "update_dts",
+ 'path': '/lib/firmware/{}.dts',
+ 'output': '/lib/firmware/{}.dtbo',
+ 'reset': False,
+ },
+ }
+ # This class removes the overlay in tear_down() resulting
+ # in stale references to methods in the RPC server. Setting
+ # this to True ensures that the RPC server clears all registered
+ # methods on unclaim() and registers them on the following claim().
+ clear_rpc_method_registry_on_unclaim = True
+
+ @classmethod
+ def generate_device_info(cls, eeprom_md, mboard_info, dboard_infos):
+ """
+ Generate dictionary describing the device.
+ """
+ # Add the default PeriphManagerBase information first
+ device_info = super().generate_device_info(
+ eeprom_md, mboard_info, dboard_infos)
+ # Then add E31x-specific information
+ mb_pid = eeprom_md.get('pid')
+ device_info['product'] = cls.pids.get(mb_pid, 'unknown')
+ return device_info
+
+ @staticmethod
+ def list_required_dt_overlays(device_info):
+ """
+ Lists device tree overlays that need to be applied before this class can
+ be used. List of strings.
+ Are applied in order.
+
+ eeprom_md -- Dictionary of info read out from the mboard EEPROM
+ device_args -- Arbitrary dictionary of info, typically user-defined
+ """
+ return [device_info['product']]
+
+
+ @staticmethod
+ def get_idle_dt_overlay(device_info):
+ """
+ Overlay to be applied to enter low power idle state.
+ """
+ # e.g. e310_sg3_idle
+ idle_overlay = device_info['product'] + '_idle'
+ return idle_overlay
+
+ ###########################################################################
+ # Ctor and device initialization tasks
+ ###########################################################################
+ def __init__(self, args):
+ """
+ Does partial initialization which loads low power idle image
+ """
+ super(e31x, self).__init__()
+ # Start clean by removing MPM-owned overlays.
+ active_overlays = self.list_active_overlays()
+ mpm_overlays = self.list_owned_overlays()
+ for overlay in active_overlays:
+ if overlay in mpm_overlays:
+ dtoverlay.rm_overlay(overlay)
+ # Apply idle overlay on boot to save power until
+ # an application tries to use the device.
+ self.args_cached = args
+ self.apply_idle_overlay()
+ self._device_initialized = False
+
+ def _init_normal(self):
+ """
+ Does full initialization
+ """
+ if self._device_initialized:
+ return
+ if self.is_idle():
+ self.remove_idle_overlay()
+ self.overlay_apply()
+ self.init_dboards(self.args_cached)
+ if not self._device_initialized:
+ # Don't try and figure out what's going on. Just give up.
+ return
+ # Initialize _do_not_reload with value from _default_args (mpm.conf)
+ self._do_not_reload = str2bool(self._default_args.get("no_reload_fpga", "False"))
+ self._tear_down = False
+ self._clock_source = None
+ self._time_source = None
+ self._available_endpoints = list(range(256))
+ self.dboard = self.dboards[E310_DBOARD_SLOT_IDX]
+ try:
+ self._init_peripherals(self.args_cached)
+ except Exception as ex:
+ self.log.error("Failed to initialize motherboard: %s", str(ex))
+ self._initialization_status = str(ex)
+ self._device_initialized = False
+
+ def _init_dboards(self, dboard_infos, override_dboard_pids, default_args):
+ """
+ Initialize all the daughterboards
+
+ dboard_infos -- List of dictionaries as returned from
+ PeriphManagerBase._get_dboard_eeprom_info()
+ override_dboard_pids -- List of dboard PIDs to force
+ default_args -- Default args
+ """
+ # Override the base class's implementation in order to avoid initializing our one "dboard"
+ # in the same way that, for example, N310's dboards are initialized. Specifically,
+ # - skip dboard EEPROM setup (we don't have one)
+ # - change the way we handle SPI devices
+ if override_dboard_pids:
+ self.log.warning("Overriding daughterboard PIDs with: {}"
+ .format(override_dboard_pids))
+ raise NotImplementedError("Can't override dboard pids")
+ # We have only one dboard
+ dboard_info = dboard_infos[0]
+ # Set up the SPI nodes
+ spi_nodes = []
+ for spi_addr in self.dboard_spimaster_addrs:
+ for spi_node in get_spidev_nodes(spi_addr):
+ bisect.insort(spi_nodes, spi_node)
+
+ self.log.trace("Found spidev nodes: {0}".format(spi_nodes))
+
+ if not spi_nodes:
+ self.log.warning("No SPI nodes for dboard %d.", E310_DBOARD_SLOT_IDX)
+ else:
+ dboard_info.update({
+ 'spi_nodes': spi_nodes,
+ 'default_args': default_args,
+ })
+
+ self.dboards.append(E31x_db(E310_DBOARD_SLOT_IDX, **dboard_info))
+ self.log.info("Found %d daughterboard(s).", len(self.dboards))
+
+ def _check_fpga_compat(self):
+ " Throw an exception if the compat numbers don't match up "
+ actual_compat = self.mboard_regs_control.get_compat_number()
+ self.log.debug("Actual FPGA compat number: {:d}.{:d}".format(
+ actual_compat[0], actual_compat[1]
+ ))
+ assert_compat_number(
+ E310_FPGA_COMPAT,
+ self.mboard_regs_control.get_compat_number(),
+ component="FPGA",
+ fail_on_old_minor=True,
+ log=self.log
+ )
+
+ def _init_ref_clock_and_time(self, default_args):
+ """
+ Initialize clock and time sources. After this function returns, the
+ reference signals going to the FPGA are valid.
+ """
+ if not self.dboards:
+ self.log.warning(
+ "No dboards found, skipping setting clock and time source "
+ "configuration."
+ )
+ self._clock_source = E310_DEFAULT_CLOCK_SOURCE
+ self._time_source = E310_DEFAULT_TIME_SOURCE
+ else:
+ self.set_clock_source(
+ default_args.get('clock_source', E310_DEFAULT_CLOCK_SOURCE)
+ )
+ self.set_time_source(
+ default_args.get('time_source', E310_DEFAULT_TIME_SOURCE)
+ )
+
+ def _init_peripherals(self, args):
+ """
+ Turn on all peripherals. This may throw an error on failure, so make
+ sure to catch it.
+
+ Peripherals are initialized in the order of least likely to fail, to most
+ likely.
+ """
+ # Sanity checks
+ assert self.mboard_info.get('product') in self.pids.values(), \
+ "Device product could not be determined!"
+ # Init Mboard Regs
+ self.mboard_regs_control = MboardRegsControl(
+ self.mboard_regs_label, self.log)
+ self.mboard_regs_control.get_git_hash()
+ self.mboard_regs_control.get_build_timestamp()
+ self._check_fpga_compat()
+ self._update_fpga_type()
+ self.crossbar_base_port = self.mboard_regs_control.get_xbar_baseport()
+ self.log.debug("crossbar base port: {}".format(self.crossbar_base_port))
+
+ # Init clocking
+ self._init_ref_clock_and_time(args)
+ # Init CHDR transports
+ self._xport_mgrs = {
+ 'liberio': E310XportMgrLiberio(self.log.getChild('liberio')),
+ }
+ # Init complete.
+ self.log.debug("mboard info: {}".format(self.mboard_info))
+
+ def _read_mboard_eeprom(self):
+ """
+ Read out mboard EEPROM.
+ Returns a tuple: (eeprom_dict, eeprom_rawdata), where the the former is
+ a de-serialized dictionary representation of the data, and the latter
+ is a binary string with the raw data.
+
+ If no EEPROM is defined, returns empty values.
+ """
+ if len(self.mboard_eeprom_addr):
+ (eeprom_head, eeprom_rawdata) = e31x_legacy_eeprom.read_eeprom(
+ True, # isMotherboard
+ get_eeprom_paths(self.mboard_eeprom_addr)[self.mboard_eeprom_path_index],
+ self.mboard_eeprom_offset,
+ e31x_legacy_eeprom.MboardEEPROM.eeprom_header_format,
+ e31x_legacy_eeprom.MboardEEPROM.eeprom_header_keys,
+ self.mboard_eeprom_max_len
+ )
+ self.log.trace("Found EEPROM metadata: `{}'"
+ .format(str(eeprom_head)))
+ self.log.trace("Read {} bytes of EEPROM data."
+ .format(len(eeprom_rawdata)))
+ return eeprom_head, eeprom_rawdata
+ # Nothing defined? Return defaults.
+ self.log.trace("No mboard EEPROM path defined. "
+ "Skipping mboard EEPROM readout.")
+ return {}, b''
+
+ def _get_dboard_eeprom_info(self):
+ """
+ Read back EEPROM info from the daughterboards
+ """
+ if self.dboard_eeprom_addr is None:
+ self.log.debug("No dboard EEPROM addresses given.")
+ return []
+ dboard_eeprom_addrs = self.dboard_eeprom_addr \
+ if isinstance(self.dboard_eeprom_addr, list) \
+ else [self.dboard_eeprom_addr]
+ dboard_eeprom_paths = []
+ self.log.trace("Identifying dboard EEPROM paths from addrs `{}'..."
+ .format(",".join(dboard_eeprom_addrs)))
+ for dboard_eeprom_addr in dboard_eeprom_addrs:
+ self.log.trace("Resolving %s...", dboard_eeprom_addr)
+ dboard_eeprom_paths += get_eeprom_paths(dboard_eeprom_addr)
+ self.log.trace("Found dboard EEPROM paths: {}"
+ .format(",".join(dboard_eeprom_paths)))
+ if len(dboard_eeprom_paths) > self.max_num_dboards:
+ self.log.warning("Found more EEPROM paths than daughterboards. "
+ "Ignoring some of them.")
+ dboard_eeprom_paths = dboard_eeprom_paths[:self.max_num_dboards]
+ dboard_info = []
+ for dboard_idx, dboard_eeprom_path in enumerate(dboard_eeprom_paths):
+ self.log.debug("Reading EEPROM info for dboard %d...", dboard_idx)
+ dboard_eeprom_md, dboard_eeprom_rawdata = e31x_legacy_eeprom.read_eeprom(
+ False, # is not motherboard.
+ dboard_eeprom_path,
+ self.dboard_eeprom_offset,
+ e31x_legacy_eeprom.DboardEEPROM.eeprom_header_format,
+ e31x_legacy_eeprom.DboardEEPROM.eeprom_header_keys,
+ self.dboard_eeprom_max_len
+ )
+ self.log.trace("Found dboard EEPROM metadata: `{}'"
+ .format(str(dboard_eeprom_md)))
+ self.log.trace("Read %d bytes of dboard EEPROM data.",
+ len(dboard_eeprom_rawdata))
+ db_pid = dboard_eeprom_md.get('pid')
+ if db_pid is None:
+ self.log.warning("No dboard PID found in dboard EEPROM!")
+ else:
+ self.log.debug("Found dboard PID in EEPROM: 0x{:04X}"
+ .format(db_pid))
+ dboard_info.append({
+ 'eeprom_md': dboard_eeprom_md,
+ 'eeprom_rawdata': dboard_eeprom_rawdata,
+ 'pid': db_pid,
+ })
+ return dboard_info
+
+ ###########################################################################
+ # Session init and deinit
+ ###########################################################################
+ def claim(self):
+ """
+ Fully initializes a device when the rpc_server claim()
+ gets called to revive the device from idle state to be used
+ by an UHD application
+ """
+ super(e31x, self).claim()
+ try:
+ self._init_normal()
+ except Exception as ex:
+ self.log.error("e31x claim() failed: %s", str(ex))
+
+ def init(self, args):
+ """
+ Calls init() on the parent class, and then programs the Ethernet
+ dispatchers accordingly.
+ """
+ if not self._device_initialized:
+ self.log.warning(
+ "Cannot run init(), device was never fully initialized!")
+ return False
+ if args.get("clock_source", "") != "":
+ self.set_clock_source(args.get("clock_source"))
+ if args.get("time_source", "") != "":
+ self.set_time_source(args.get("time_source"))
+ if "no_reload_fpga" in args:
+ self._do_not_reload = str2bool(args.get("no_reload_fpga")) or args.get("no_reload_fpga") == ""
+ result = super(e31x, self).init(args)
+ for xport_mgr in itervalues(self._xport_mgrs):
+ xport_mgr.init(args)
+ return result
+
+
+ def apply_idle_overlay(self):
+ """
+ Load all overlays required to go into idle power savings mode.
+ """
+ idle_overlay = self.get_idle_dt_overlay(self.device_info)
+ self.log.debug("Motherboard requests device tree overlay for Idle power savings mode: {}".format(
+ idle_overlay
+ ))
+ dtoverlay.apply_overlay_safe(idle_overlay)
+
+ def remove_idle_overlay(self):
+ """
+ Remove idle mode overlay.
+ """
+ idle_overlay = self.get_idle_dt_overlay(self.device_info)
+ self.log.trace("Removing Idle overlay: {}".format(
+ idle_overlay
+ ))
+ dtoverlay.rm_overlay(idle_overlay)
+
+ def list_owned_overlays(self):
+ """
+ Lists all overlays that can be possibly applied by MPM.
+ """
+ all_overlays = self.list_required_dt_overlays(self.device_info)
+ all_overlays.append(self.get_idle_dt_overlay(self.device_info))
+ return all_overlays
+
+ def deinit(self):
+ """
+ Clean up after a UHD session terminates.
+ """
+ if not self._device_initialized:
+ self.log.warning(
+ "Cannot run deinit(), device was never fully initialized!")
+ return
+ super(e31x, self).deinit()
+ for xport_mgr in itervalues(self._xport_mgrs):
+ xport_mgr.deinit()
+ self.log.trace("Resetting SID pool...")
+ self._available_endpoints = list(range(256))
+ if not self._do_not_reload:
+ self.tear_down()
+ # Reset back to value from _default_args (mpm.conf)
+ self._do_not_reload = str2bool(self._default_args.get("no_reload_fpga", "False"))
+
+ def tear_down(self):
+ """
+ Tear down all members that need to be specially handled before
+ deconstruction.
+ For E310, this means the overlay.
+ """
+ self.log.trace("Tearing down E310 device...")
+ self._tear_down = True
+ self.dboards = []
+ self.dboard = None
+ self.mboard_regs_control = None
+ self._device_initialized = False
+ active_overlays = self.list_active_overlays()
+ self.log.trace("E310 has active device tree overlays: {}".format(
+ active_overlays
+ ))
+ for overlay in active_overlays:
+ dtoverlay.rm_overlay(overlay)
+ self.apply_idle_overlay()
+
+ def is_idle(self):
+ """
+ Determine if the device is in the idle state.
+ """
+ active_overlays = self.list_active_overlays()
+ idle_overlay = self.get_idle_dt_overlay(self.device_info)
+ is_idle = idle_overlay in active_overlays
+ if is_idle:
+ self.log.trace("Found idle overlay: %s", idle_overlay)
+ return is_idle
+
+ ###########################################################################
+ # Transport API
+ ###########################################################################
+ def request_xport(
+ self,
+ dst_address,
+ suggested_src_address,
+ xport_type
+ ):
+ """
+ See PeriphManagerBase.request_xport() for docs.
+ """
+ # Try suggested address first, then just pick the first available one:
+ src_address = suggested_src_address
+ if src_address not in self._available_endpoints:
+ if not self._available_endpoints:
+ raise RuntimeError(
+ "Depleted pool of SID endpoints for this device!")
+ else:
+ src_address = self._available_endpoints[0]
+ sid = SID(src_address << 16 | dst_address)
+ # Note: This SID may change its source address!
+ self.log.trace(
+ "request_xport(dst=0x%04X, suggested_src_address=0x%04X, xport_type=%s): " \
+ "operating on temporary SID: %s",
+ dst_address, suggested_src_address, str(xport_type), str(sid))
+ assert self.mboard_info['rpc_connection'] in ('local')
+ if self.mboard_info['rpc_connection'] == 'local':
+ return self._xport_mgrs['liberio'].request_xport(
+ sid,
+ xport_type,
+ )
+
+ def commit_xport(self, xport_info):
+ """
+ See PeriphManagerBase.commit_xport() for docs.
+
+ Reminder: All connections are incoming, i.e. "send" or "TX" means
+ remote device to local device, and "receive" or "RX" means this local
+ device to remote device. "Remote device" can be, for example, a UHD
+ session.
+ """
+ ## Go, go, go
+ assert self.mboard_info['rpc_connection'] in ('local')
+ sid = SID(xport_info['send_sid'])
+ self._available_endpoints.remove(sid.src_ep)
+ self.log.debug("Committing transport for SID %s, xport info: %s",
+ str(sid), str(xport_info))
+ if self.mboard_info['rpc_connection'] == 'local':
+ return self._xport_mgrs['liberio'].commit_xport(sid, xport_info)
+
+ ###########################################################################
+ # Device info
+ ###########################################################################
+ def get_device_info_dyn(self):
+ """
+ Append the device info with current IP addresses.
+ """
+ if not self._device_initialized:
+ return {}
+ device_info = {}
+ device_info.update({
+ 'fpga_version': "{}.{}".format(
+ *self.mboard_regs_control.get_compat_number()),
+ 'fpga_version_hash': "{:x}.{}".format(
+ *self.mboard_regs_control.get_git_hash()),
+ 'fpga': self.updateable_components.get('fpga', {}).get('type', ""),
+ })
+ return device_info
+
+ ###########################################################################
+ # Clock/Time API
+ ###########################################################################
+ def get_clock_sources(self):
+ " Lists all available clock sources. "
+ self.log.trace("Listing available clock sources...")
+ return ('internal',)
+
+ def get_clock_source(self):
+ " Returns the currently selected clock source "
+ return self._clock_source
+
+ def set_clock_source(self, *args):
+ """
+ Switch reference clock.
+
+ Throws if clock_source is not a valid value.
+ """
+ clock_source = args[0]
+ assert clock_source in self.get_clock_sources()
+ self.log.debug("Setting clock source to `{}'".format(clock_source))
+ if clock_source == self.get_clock_source():
+ self.log.trace("Nothing to do -- clock source already set.")
+ return
+ self._clock_source = clock_source
+ self.mboard_regs_control.set_clock_source(clock_source)
+
+ def get_time_sources(self):
+ " Returns list of valid time sources "
+ return ['internal', 'external', 'gpsdo']
+
+ def get_time_source(self):
+ " Return the currently selected time source "
+ return self._time_source
+
+ def set_time_source(self, time_source):
+ " Set a time source "
+ assert time_source in self.get_time_sources()
+ if time_source == self.get_time_source():
+ self.log.trace("Nothing to do -- time source already set.")
+ return
+ self._time_source = time_source
+ self.mboard_regs_control.set_time_source(time_source)
+
+ ###########################################################################
+ # Hardware peripheral controls
+ ###########################################################################
+
+ def set_fp_gpio_master(self, value):
+ """set driver for front panel GPIO
+ Arguments:
+ value {unsigned} -- value is a single bit bit mask of 12 pins GPIO
+ """
+ self.mboard_regs_control.set_fp_gpio_master(value)
+
+ def get_fp_gpio_master(self):
+ """get "who" is driving front panel gpio
+ The return value is a bit mask of 8 pins GPIO.
+ 0: means the pin is driven by PL
+ 1: means the pin is driven by PS
+ """
+ return self.mboard_regs_control.get_fp_gpio_master()
+
+ def set_fp_gpio_radio_src(self, value):
+ """set driver for front panel GPIO
+ Arguments:
+ value {unsigned} -- value is 2-bit bit mask of 8 pins GPIO
+ 00: means the pin is driven by radio 0
+ 01: means the pin is driven by radio 1
+ """
+ self.mboard_regs_control.set_fp_gpio_radio_src(value)
+
+ def get_fp_gpio_radio_src(self):
+ """get which radio is driving front panel gpio
+ The return value is 2-bit bit mask of 8 pins GPIO.
+ 00: means the pin is driven by radio 0
+ 01: means the pin is driven by radio 1
+ """
+ return self.mboard_regs_control.get_fp_gpio_radio_src()
+
+ def set_channel_mode(self, channel_mode):
+ "Set channel mode in FPGA and select which tx channel to use"
+ self.mboard_regs_control.set_channel_mode(channel_mode)
+
+ ###########################################################################
+ # Sensors
+ ###########################################################################
+ def get_ref_lock_sensor(self):
+ """
+ #TODO: Where is ref lock signal coming from?
+ """
+ self.log.trace("Querying ref lock status.")
+ lock_status = bool(self.mboard_regs_control.get_refclk_lock())
+ return {
+ 'name': 'ref_locked',
+ 'type': 'BOOLEAN',
+ 'unit': 'locked' if lock_status else 'unlocked',
+ 'value': str(lock_status).lower(),
+ }
+
+ def get_mb_temp_sensor(self):
+ """
+ Get temperature sensor reading of the E310.
+ """
+ self.log.trace("Reading temperature.")
+ temp = '-1'
+ raw_val = {}
+ data_probes = ['temp1_input']
+ try:
+ for data_probe in data_probes:
+ raw_val[data_probe] = read_sysfs_sensors_value('jc-42.4-temp', data_probe, 'hwmon', 'name')[0]
+ temp = str(raw_val['temp1_input'] / 1000)
+ except ValueError:
+ self.log.warning("Error when converting temperature value")
+ except KeyError:
+ self.log.warning("Can't read temp on thermal_zone".format(sensor))
+ return {
+ 'name': 'temp_mb',
+ 'type': 'REALNUM',
+ 'unit': 'C',
+ 'value': temp
+ }
+
+ def get_fpga_temp_sensor(self):
+ """
+ Get temperature sensor reading of the E310.
+ """
+ self.log.trace("Reading temperature.")
+ temp = '-1'
+ raw_val = {}
+ data_probes = ['in_temp0_raw', 'in_temp0_scale', 'in_temp0_offset']
+ try:
+ for data_probe in data_probes:
+ raw_val[data_probe] = read_sysfs_sensors_value('xadc', data_probe, 'iio', 'name')[0]
+ temp = str((raw_val['in_temp0_raw'] + raw_val['in_temp0_offset']) * raw_val['in_temp0_scale'] / 1000)
+ except ValueError:
+ self.log.warning("Error when converting temperature value")
+ except KeyError:
+ self.log.warning("Can't read temp on thermal_zone".format(sensor))
+ return {
+ 'name': 'temp_fpga',
+ 'type': 'REALNUM',
+ 'unit': 'C',
+ 'value': temp
+ }
+
+ ###########################################################################
+ # EEPROMs
+ ###########################################################################
+ def get_mb_eeprom(self):
+ """
+ Return a dictionary with EEPROM contents.
+
+ All key/value pairs are string -> string.
+
+ We don't actually return the EEPROM contents, instead, we return the
+ mboard info again. This filters the EEPROM contents to what we think
+ the user wants to know/see.
+ """
+ return self.mboard_info
+
+ def set_mb_eeprom(self, eeprom_vals):
+ """
+ See PeriphManagerBase.set_mb_eeprom() for docs.
+ """
+ self.log.warn("Called set_mb_eeprom(), but not implemented!")
+ raise NotImplementedError
+
+ def get_db_eeprom(self, dboard_idx):
+ """
+ See PeriphManagerBase.get_db_eeprom() for docs.
+ """
+ if dboard_idx != E310_DBOARD_SLOT_IDX:
+ self.log.warn("Trying to access invalid dboard index {}. "
+ "Using the only dboard.".format(dboard_idx))
+ db_eeprom_data = copy.copy(self.dboard.device_info)
+ return db_eeprom_data
+
+ def set_db_eeprom(self, dboard_idx, eeprom_data):
+ self.log.warn("Called set_db_eeprom(), but not implemented!")
+ raise NotImplementedError
+
+ ###########################################################################
+ # Component updating
+ ###########################################################################
+ # Note: Component updating functions defined by ZynqComponents
+ @no_rpc
+ def _update_fpga_type(self):
+ """Update the fpga type stored in the updateable components"""
+ fpga_type = self.mboard_regs_control.get_fpga_type()
+ self.log.debug("Updating mboard FPGA type info to {}".format(fpga_type))
+ self.updateable_components['fpga']['type'] = fpga_type
diff --git a/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py b/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py
new file mode 100644
index 000000000..0b166e5bc
--- /dev/null
+++ b/mpm/python/usrp_mpm/periph_manager/e31x_periphs.py
@@ -0,0 +1,297 @@
+#
+# Copyright 2018 Ettus Research, a National Instruments Company
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+"""
+E310 peripherals
+"""
+
+import datetime
+import math
+from usrp_mpm.sys_utils.sysfs_gpio import SysFSGPIO, GPIOBank
+from usrp_mpm.sys_utils.uio import UIO
+
+class FrontpanelGPIO(GPIOBank):
+ """
+ Abstraction layer for the front panel GPIO
+ """
+ EMIO_BASE = 54
+ FP_GPIO_OFFSET = 32 # Bit offset within the ps_gpio_* pins
+
+ def __init__(self, ddr):
+ GPIOBank.__init__(
+ self,
+ {'label': 'zynq_gpio'},
+ self.FP_GPIO_OFFSET + self.EMIO_BASE,
+ 0xFF, # use_mask
+ ddr
+ )
+
+class MboardRegsControl(object):
+ """
+ Control the FPGA Motherboard registers
+ """
+ # Motherboard registers
+ MB_COMPAT_NUM = 0x0000
+ MB_DATESTAMP = 0x0004
+ MB_GIT_HASH = 0x0008
+ MB_SCRATCH = 0x000C
+ MB_NUM_CE = 0x0010
+ MB_NUM_IO_CE = 0x0014
+ MB_CLOCK_CTRL = 0x0018
+ MB_XADC_RB = 0x001C
+ MB_BUS_CLK_RATE = 0x0020
+ MB_BUS_COUNTER = 0x0024
+ MB_GPIO_MASTER = 0x0030
+ MB_GPIO_RADIO_SRC = 0x0034
+ MB_GPS_CTRL = 0x0038
+ MB_GPS_STATUS = 0x003C
+ MB_DBOARD_CTRL = 0x0040
+ MB_DBOARD_STATUS = 0x0044
+ MB_XBAR_BASEPORT = 0x0048
+
+ # Bitfield locations for the MB_CLOCK_CTRL register.
+ MB_CLOCK_CTRL_PPS_SEL_INT = 0
+ MB_CLOCK_CTRL_PPS_SEL_EXT = 1
+ MB_CLOCK_CTRL_REF_CLK_LOCKED = 2
+
+ # Bitfield locations for the MB_GPS_CTRL register.
+ #FIXME: Update for E310
+ MB_GPS_CTRL_PWR_EN = 0
+ MB_GPS_CTRL_RST_N = 1
+ MB_GPS_CTRL_INITSURV_N = 2
+
+ # Bitfield locations for the MB_GPS_STATUS register.
+ #FIXME: Update for E310
+ MB_GPS_STATUS_LOCK = 0
+ MB_GPS_STATUS_ALARM = 1
+ MB_GPS_STATUS_PHASELOCK = 2
+ MB_GPS_STATUS_SURVEY = 3
+ MB_GPS_STATUS_WARMUP = 4
+
+ # Bitfield locations for the MB_DBOARD_CTRL register.
+ MB_DBOARD_CTRL_MIMO = 0
+ MB_DBOARD_CTRL_TX_CHAN_SEL = 1
+
+ # Bitfield locations for the MB_DBOARD_STATUS register.
+ MB_DBOARD_STATUS_RX_LOCK = 6
+ MB_DBOARD_STATUS_TX_LOCK = 7
+
+ def __init__(self, label, log):
+ self.log = log
+ self.regs = UIO(
+ label=label,
+ read_only=False
+ )
+ self.poke32 = self.regs.poke32
+ self.peek32 = self.regs.peek32
+
+ def get_compat_number(self):
+ """get FPGA compat number
+
+ This function reads back FPGA compat number.
+ The return is a tuple of
+ 2 numbers: (major compat number, minor compat number )
+ """
+ with self.regs:
+ compat_number = self.peek32(self.MB_COMPAT_NUM)
+ minor = compat_number & 0xff
+ major = (compat_number>>16) & 0xff
+ return (major, minor)
+
+ def set_fp_gpio_master(self, value):
+ """set driver for front panel GPIO
+ Arguments:
+ value {unsigned} -- value is a single bit bit mask of 8 pins GPIO
+ """
+ with self.regs:
+ return self.poke32(self.MB_GPIO_MASTER, value)
+
+ def get_fp_gpio_master(self):
+ """get "who" is driving front panel gpio
+ The return value is a bit mask of 8 pins GPIO.
+ 0: means the pin is driven by PL
+ 1: means the pin is driven by PS
+ """
+ with self.regs:
+ return self.peek32(self.MB_GPIO_MASTER) & 0xfff
+
+ def set_fp_gpio_radio_src(self, value):
+ """set driver for front panel GPIO
+ Arguments:
+ value {unsigned} -- value is 2-bit bit mask of 8 pins GPIO
+ 00: means the pin is driven by radio 0
+ 01: means the pin is driven by radio 1
+ """
+ with self.regs:
+ return self.poke32(self.MB_GPIO_RADIO_SRC, value)
+
+ def get_fp_gpio_radio_src(self):
+ """get which radio is driving front panel gpio
+ The return value is 2-bit bit mask of 8 pins GPIO.
+ 00: means the pin is driven by radio 0
+ 01: means the pin is driven by radio 1
+ """
+ with self.regs:
+ return self.peek32(self.MB_GPIO_RADIO_SRC) & 0xffffff
+
+ def get_build_timestamp(self):
+ """
+ Returns the build date/time for the FPGA image.
+ The return is datetime string with the ISO 8601 format
+ (YYYY-MM-DD HH:MM:SS.mmmmmm)
+ """
+ with self.regs:
+ datestamp_rb = self.peek32(self.MB_DATESTAMP)
+ if datestamp_rb > 0:
+ dt_str = datetime.datetime(
+ year=((datestamp_rb>>17)&0x3F)+2000,
+ month=(datestamp_rb>>23)&0x0F,
+ day=(datestamp_rb>>27)&0x1F,
+ hour=(datestamp_rb>>12)&0x1F,
+ minute=(datestamp_rb>>6)&0x3F,
+ second=((datestamp_rb>>0)&0x3F))
+ self.log.trace("FPGA build timestamp: {}".format(str(dt_str)))
+ return str(dt_str)
+ else:
+ # Compatibility with FPGAs without datestamp capability
+ return ''
+
+ def get_git_hash(self):
+ """
+ Returns the GIT hash for the FPGA build.
+ The return is a tuple of
+ 2 numbers: (short git hash, bool: is the tree dirty?)
+ """
+ with self.regs:
+ git_hash_rb = self.peek32(self.MB_GIT_HASH)
+ git_hash = git_hash_rb & 0x0FFFFFFF
+ tree_dirty = ((git_hash_rb & 0xF0000000) > 0)
+ dirtiness_qualifier = 'dirty' if tree_dirty else 'clean'
+ self.log.trace("FPGA build GIT Hash: {:07x} ({})".format(
+ git_hash, dirtiness_qualifier))
+ return (git_hash, dirtiness_qualifier)
+
+ def set_time_source(self, time_source):
+ """
+ Set time source
+ """
+ pps_sel_val = 0x0
+ if time_source == 'internal':
+ self.log.trace("Setting time source to internal")
+ pps_sel_val = self.MB_CLOCK_CTRL_PPS_SEL_INT
+ elif time_source == 'gpsdo':
+ self.log.debug("Setting time source to gpsdo...")
+ pps_sel_val = self.MB_CLOCK_CTRL_PPS_SEL_GPS
+ elif time_source == 'external':
+ self.log.debug("Setting time source to external...")
+ pps_sel_val = self.MB_CLOCK_CTRL_PPS_SEL_EXT
+ else:
+ assert False, "Cannot set to invalid time source: {}".format(time_source)
+ with self.regs:
+ reg_val = self.peek32(self.MB_CLOCK_CTRL) & 0xFFFFFF90
+ # prevent glitches by writing a cleared value first, then the final value.
+ self.poke32(self.MB_CLOCK_CTRL, reg_val)
+ reg_val = reg_val | (pps_sel_val & 0x6F)
+ self.log.trace("Writing MB_CLOCK_CTRL to 0x{:08X}".format(reg_val))
+ self.poke32(self.MB_CLOCK_CTRL, reg_val)
+
+ def set_clock_source(self, clock_source):
+ """
+ Set clock source
+ """
+ if clock_source == 'internal':
+ self.log.trace("Setting clock source to internal")
+ else:
+ assert False, "Cannot set to invalid clock source: {}".format(clock_source)
+
+ def get_fpga_type(self):
+ """
+ Reads the type of the FPGA image currently loaded
+ Returns a string with the type (SG1, SG3)
+ """
+ #TODO: Add SG1 and SG3?
+ return ""
+
+ def get_gps_status(self):
+ """
+ Get GPS status
+ """
+ mask = 0x1F
+ with self.regs:
+ gps_status = self.peek32(self.MB_GPS_STATUS) & mask
+ return gps_status
+
+ def get_refclk_lock(self):
+ """
+ Check the status of the reference clock in FPGA.
+ """
+ mask = 0b1 << self.MB_CLOCK_CTRL_REF_CLK_LOCKED
+ with self.regs:
+ reg_val = self.peek32(self.MB_CLOCK_CTRL)
+ locked = (reg_val & mask) > 0
+ if not locked:
+ self.log.warning("Reference Clock reporting unlocked. "
+ "MB_CLOCK_CTRL reg: 0x{:08X}".format(reg_val))
+ else:
+ self.log.trace("Reference Clock locked!")
+ return locked
+
+ def set_channel_mode(self, channel_mode):
+ """
+ Set channel mode in FPGA and select which tx channel to use
+ channel mode = "MIMO" for mimo
+ channel mode = "SISO_TX1", "SISO_TX0" for siso tx1, tx0 respectively.
+ """
+ with self.regs:
+ reg_val = self.peek32(self.MB_DBOARD_CTRL)
+ if channel_mode == "MIMO":
+ reg_val = (0b1 << self.MB_DBOARD_CTRL_MIMO)
+ self.log.trace("Setting channel mode in AD9361 interface: {}".format("2R2T" if channel_mode == 2 else "1R1T"))
+ else:
+ # Warn if user tries to set either tx0/tx1 in mimo mode
+ # as both will be set automatically
+ if channel_mode == "SISO_TX1":
+ # in SISO mode, Channel 1
+ reg_val = (0b1 << self.MB_DBOARD_CTRL_TX_CHAN_SEL) | (0b0 << self.MB_DBOARD_CTRL_MIMO)
+ self.log.trace("Setting TX channel in AD9361 interface to: TX1")
+ elif channel_mode == "SISO_TX0":
+ # in SISO mode, Channel 0
+ reg_val = (0b0 << self.MB_DBOARD_CTRL_TX_CHAN_SEL) | (0b0 << self.MB_DBOARD_CTRL_MIMO)
+ self.log.trace("Setting TX channel in AD9361 interface to: TX0")
+ self.log.trace("Writing MB_DBOARD_CTRL to 0x{:08X}".format(reg_val))
+ self.poke32(self.MB_DBOARD_CTRL, reg_val)
+
+ def get_ad9361_tx_lo_lock(self):
+ """
+ Check the status of TX LO lock from CTRL_OUT pins from Catalina
+ """
+ mask = 0b1 << self.MB_DBOARD_STATUS_TX_LOCK
+ with self.regs:
+ reg_val = self.peek32(self.MB_DBOARD_STATUS)
+ locked = (reg_val & mask) > 0
+ if not locked:
+ self.log.warning("TX RF PLL reporting unlocked. ")
+ else:
+ self.log.trace("TX RF PLL locked")
+ return locked
+
+ def get_ad9361_rx_lo_lock(self):
+ """
+ Check the status of RX LO lock from CTRL_OUT pins from Catalina
+ """
+ mask = 0b1 << self.MB_DBOARD_STATUS_RX_LOCK
+ with self.regs:
+ reg_val = self.peek32(self.MB_DBOARD_STATUS)
+ locked = (reg_val & mask) > 0
+ if not locked:
+ self.log.warning("RX RF PLL reporting unlocked. ")
+ else:
+ self.log.trace("RX RF PLL locked")
+ return locked
+
+ def get_xbar_baseport(self):
+ "Get the RFNoC crossbar base port"
+ with self.regs:
+ return self.peek32(self.MB_XBAR_BASEPORT)
diff --git a/mpm/python/usrp_mpm/rpc_server.py b/mpm/python/usrp_mpm/rpc_server.py
index c67bf769b..80b4eb44e 100644
--- a/mpm/python/usrp_mpm/rpc_server.py
+++ b/mpm/python/usrp_mpm/rpc_server.py
@@ -286,6 +286,8 @@ class MPMServer(RPCServer):
self._state.claim_status.value = True
self.periph_manager.claimed = True
self.periph_manager.claim()
+ if self.periph_manager.clear_rpc_method_registry_on_unclaim:
+ self._init_rpc_calls(self.periph_manager)
self._state.lock.release()
self.session_id = session_id + " ({})".format(self.client_host)
self._reset_timer()
@@ -337,6 +339,8 @@ class MPMServer(RPCServer):
self._state.claim_status.value = False
self._state.claim_token.value = b''
self.session_id = None
+ if self.periph_manager.clear_rpc_method_registry_on_unclaim:
+ self.clear_method_registry()
try:
self.periph_manager.claimed = False
self.periph_manager.unclaim()
@@ -451,19 +455,13 @@ class MPMServer(RPCServer):
###########################################################################
# Update components
###########################################################################
- def reset_mgr(self):
+ def clear_method_registry(self):
"""
- Reset the Peripheral Manager for this RPC server.
+ Clear all the methods in the RPC server method cache.
"""
- self.log.info("Resetting peripheral manager.")
- self.periph_manager.tear_down()
- self.periph_manager = None
- self.periph_manager = self._mgr_generator()
- self._init_rpc_calls(self.periph_manager)
# RPCServer caches RPC methods, but that cache is not accessible here
# (because Cython). Re-running `RPCServer.__init__` clears that cache,
- # and allows us to register new RPC methods (which we need to do because
- # we're resetting the PeriphManager).
+ # and allows us to register new RPC methods.
# A note on maintenance: This has been deemed safe through inspection of
# the RPCServer source code. However, this is not typical Python, and
# changes in future versions of RPCServer may cause issues.
@@ -471,6 +469,19 @@ class MPMServer(RPCServer):
pack_params={'use_bin_type': True},
)
+ def reset_mgr(self):
+ """
+ Reset the Peripheral Manager for this RPC server.
+ """
+ self.log.info("Resetting peripheral manager.")
+ self.periph_manager.tear_down()
+ self.periph_manager = None
+ self.periph_manager = self._mgr_generator()
+ self._init_rpc_calls(self.periph_manager)
+ # Clear the method cache in order to remove stale references to
+ # methods from the old peripheral manager (the one before reset)
+ self.clear_method_registry()
+
def update_component(self, token, file_metadata_l, data_l):
""""
Updates the device component files specified by the metadata and data
diff --git a/mpm/tools/CMakeLists.txt b/mpm/tools/CMakeLists.txt
index 05838b897..245720656 100644
--- a/mpm/tools/CMakeLists.txt
+++ b/mpm/tools/CMakeLists.txt
@@ -13,7 +13,7 @@ install(PROGRAMS
set(eeprom_tool_sources)
set(eeprom_tool_libs)
-if(ENABLE_LIBMPM)
+if(ENABLE_LIBMPM AND NOT ENABLE_E300)
message(STATUS "Adding MPM EEPROM tools...")
set(eeprom_tool_libs eeprom.c)
list(APPEND eeprom_tool_sources
@@ -23,7 +23,7 @@ if(ENABLE_LIBMPM)
eeprom-init.c
eeprom-set-flags.c
)
-endif(ENABLE_LIBMPM)
+endif(ENABLE_LIBMPM AND NOT ENABLE_E300)
if(ENABLE_MYKONOS)
message(STATUS "Adding N3XX-specific EEPROM tools...")
set(eeprom_tool_libs eeprom.c)