// // Copyright 2010-2012 Ettus Research LLC // Copyright 2018 Ettus Research, a National Instruments Company // // SPDX-License-Identifier: GPL-3.0-or-later // #include #include #include #include #include #include #include #include #include using namespace uhd; using namespace uhd::usrp; /*********************************************************************** * Constants **********************************************************************/ namespace { constexpr uint32_t BASIC_TX_PID = 0x0000; constexpr uint32_t BASIC_RX_PID = 0x0001; constexpr uint32_t LF_TX_PID = 0x000E; constexpr uint32_t LF_RX_PID = 0x000F; constexpr double BASIC_MAX_BANDWIDTH = 250e6; // Hz constexpr double LF_MAX_BANDWIDTH = 32e6; // Hz const std::map subdev_bandwidth_scalar{ {"A", 1.0}, {"B", 1.0}, {"AB", 2.0}, {"BA", 2.0} }; const uhd::dict sd_name_to_conn = boost::assign::map_list_of ("AB", "IQ") ("BA", "QI") ("A", "I") ("B", "Q") ; } /*********************************************************************** * The basic and lf boards: * They share a common class because only the frequency bounds differ. **********************************************************************/ class basic_rx : public rx_dboard_base{ public: basic_rx(ctor_args_t args, double max_freq); virtual ~basic_rx(void); private: void set_rx_ant(const std::string& ant); double _max_freq; }; class basic_tx : public tx_dboard_base{ public: basic_tx(ctor_args_t args, double max_freq); virtual ~basic_tx(void); private: double _max_freq; }; /*********************************************************************** * Register the basic and LF dboards **********************************************************************/ static dboard_base::sptr make_basic_rx(dboard_base::ctor_args_t args){ return dboard_base::sptr(new basic_rx(args, BASIC_MAX_BANDWIDTH)); } static dboard_base::sptr make_basic_tx(dboard_base::ctor_args_t args){ return dboard_base::sptr(new basic_tx(args, BASIC_MAX_BANDWIDTH)); } static dboard_base::sptr make_lf_rx(dboard_base::ctor_args_t args){ return dboard_base::sptr(new basic_rx(args, LF_MAX_BANDWIDTH)); } static dboard_base::sptr make_lf_tx(dboard_base::ctor_args_t args){ return dboard_base::sptr(new basic_tx(args, LF_MAX_BANDWIDTH)); } UHD_STATIC_BLOCK(reg_basic_and_lf_dboards){ dboard_manager::register_dboard(BASIC_TX_PID, &make_basic_tx, "Basic TX", sd_name_to_conn.keys()); dboard_manager::register_dboard(BASIC_RX_PID, &make_basic_rx, "Basic RX", sd_name_to_conn.keys()); dboard_manager::register_dboard(LF_TX_PID, &make_lf_tx, "LF TX", sd_name_to_conn.keys()); dboard_manager::register_dboard(LF_RX_PID, &make_lf_rx, "LF RX", sd_name_to_conn.keys()); } /*********************************************************************** * Basic and LF RX dboard **********************************************************************/ basic_rx::basic_rx(ctor_args_t args, double max_freq) : rx_dboard_base(args), _max_freq(max_freq) { const std::string fe_name(get_subdev_name()); const std::string fe_conn(sd_name_to_conn[fe_name]); const std::string db_name(str( boost::format("%s (%s)") % ((get_rx_id() == BASIC_RX_PID) ? "BasicRX" : "LFRX") % fe_name)); UHD_LOG_TRACE("BASICRX", "Initializing driver for: " << db_name << " IQ connection type: " << fe_conn); const bool has_fe_conn_settings = get_iface()->has_set_fe_connection(dboard_iface::UNIT_RX); UHD_LOG_TRACE("BASICRX", "Access to FE connection settings: " << (has_fe_conn_settings ? "Yes" : "No")); std::vector antenna_options = has_fe_conn_settings ? sd_name_to_conn.keys() : std::vector(1, ""); //////////////////////////////////////////////////////////////////// // Register properties //////////////////////////////////////////////////////////////////// this->get_rx_subtree()->create("name").set(db_name); this->get_rx_subtree()->create("gains"); //phony property so this dir exists this->get_rx_subtree()->create("freq/value") .set_publisher([](){ return 0.0; }); this->get_rx_subtree()->create("freq/range") .set(freq_range_t(-_max_freq, +_max_freq)); this->get_rx_subtree()->create("antenna/value") .set(has_fe_conn_settings ? fe_name : ""); if (has_fe_conn_settings) { this->get_rx_subtree()->access("antenna/value") .add_coerced_subscriber([this](const std::string& ant){ this->set_rx_ant(ant); }) ; } this->get_rx_subtree()->create>("antenna/options") .set(antenna_options); this->get_rx_subtree()->create("sensors"); //phony property so this dir exists this->get_rx_subtree()->create("connection") .set(sd_name_to_conn[get_subdev_name()]); this->get_rx_subtree()->create("enabled") .set(true); //always enabled this->get_rx_subtree()->create("use_lo_offset") .set(false); this->get_rx_subtree()->create("bandwidth/value") .set(subdev_bandwidth_scalar.at(get_subdev_name())*_max_freq); this->get_rx_subtree()->create("bandwidth/range") .set(freq_range_t( subdev_bandwidth_scalar.at(get_subdev_name())*_max_freq, subdev_bandwidth_scalar.at(get_subdev_name())*_max_freq)); //disable RX dboard clock by default this->get_iface()->set_clock_enabled(dboard_iface::UNIT_RX, false); //set GPIOs to output 0x0000 to decrease noise pickup this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_RX, 0x0000); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_RX, 0xFFFF); this->get_iface()->set_gpio_out(dboard_iface::UNIT_RX, 0x0000); } basic_rx::~basic_rx(void){ /* NOP */ } void basic_rx::set_rx_ant(const std::string& ant) { UHD_ASSERT_THROW(get_iface()->has_set_fe_connection(dboard_iface::UNIT_RX)); UHD_LOG_TRACE("BASICRX", "Setting antenna value to: " << ant); get_iface()->set_fe_connection( dboard_iface::UNIT_RX, get_subdev_name(), usrp::fe_connection_t(sd_name_to_conn[ant], 0.0 /* IF */) ); } /*********************************************************************** * Basic and LF TX dboard **********************************************************************/ basic_tx::basic_tx(ctor_args_t args, double max_freq) : tx_dboard_base(args){ _max_freq = max_freq; //this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, true); //////////////////////////////////////////////////////////////////// // Register properties //////////////////////////////////////////////////////////////////// if (get_tx_id() == BASIC_TX_PID) { this->get_tx_subtree()->create("name").set( std::string(str(boost::format("BasicTX (%s)") % get_subdev_name() ))); } else { this->get_tx_subtree()->create("name").set( std::string(str(boost::format("LFTX (%s)") % get_subdev_name() ))); } this->get_tx_subtree()->create("gains"); //phony property so this dir exists this->get_tx_subtree()->create("freq/value") .set_publisher([](){ return 0.0; }); this->get_tx_subtree()->create("freq/range") .set(freq_range_t(-_max_freq, +_max_freq)); this->get_tx_subtree()->create("antenna/value") .set(""); this->get_tx_subtree()->create>("antenna/options") .set({""}); this->get_tx_subtree()->create("sensors"); //phony property so this dir exists this->get_tx_subtree()->create("connection") .set(sd_name_to_conn[get_subdev_name()]); this->get_tx_subtree()->create("enabled") .set(true); //always enabled this->get_tx_subtree()->create("use_lo_offset") .set(false); this->get_tx_subtree()->create("bandwidth/value") .set(subdev_bandwidth_scalar.at(get_subdev_name())*_max_freq); this->get_tx_subtree()->create("bandwidth/range") .set(freq_range_t( subdev_bandwidth_scalar.at(get_subdev_name())*_max_freq, subdev_bandwidth_scalar.at(get_subdev_name())*_max_freq)); //disable TX dboard clock by default this->get_iface()->set_clock_enabled(dboard_iface::UNIT_TX, false); //set GPIOs to output 0x0000 to decrease noise pickup this->get_iface()->set_pin_ctrl(dboard_iface::UNIT_TX, 0x0000); this->get_iface()->set_gpio_ddr(dboard_iface::UNIT_TX, 0xFFFF); this->get_iface()->set_gpio_out(dboard_iface::UNIT_TX, 0x0000); } basic_tx::~basic_tx(void){ /* NOP */ }