diff options
Diffstat (limited to 'host/lib/usrp/e300/e300_impl.cpp')
-rw-r--r-- | host/lib/usrp/e300/e300_impl.cpp | 352 |
1 files changed, 166 insertions, 186 deletions
diff --git a/host/lib/usrp/e300/e300_impl.cpp b/host/lib/usrp/e300/e300_impl.cpp index a08168eab..6d66e83c0 100644 --- a/host/lib/usrp/e300/e300_impl.cpp +++ b/host/lib/usrp/e300/e300_impl.cpp @@ -1,5 +1,5 @@ // -// Copyright 2013-2014 Ettus Research LLC +// Copyright 2013-2015 Ettus Research LLC // // 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 @@ -121,7 +121,7 @@ static bool is_loopback(const if_addrs_t &if_addrs) return if_addrs.inet == asio::ip::address_v4::loopback().to_string(); } -static device_addrs_t e300_find(const device_addr_t &multi_dev_hint) +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); @@ -268,6 +268,36 @@ static device::sptr e300_make(const device_addr_t &device_addr) 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 boost::uint16_t pid = boost::lexical_cast<boost::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_MB: + fpga_image = device_addr.cast<std::string>("fpga", + find_image_path(E310_FPGA_FILE_NAME)); + idle_image = find_image_path(E310_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(E300_FPGA_IDLE_FILE_NAME); + break; + case e300_eeprom_manager::UNKNOWN: + default: + UHD_MSG(warning) << "Unknown motherboard type, loading e300 image." + << std::endl; + fpga_image = device_addr.cast<std::string>("fpga", + find_image_path(E300_FPGA_FILE_NAME)); + idle_image = find_image_path(E300_FPGA_IDLE_FILE_NAME); + break; + } +} + /*********************************************************************** * Structors **********************************************************************/ @@ -286,33 +316,10 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) if (_xport_path == AXI) { _do_not_reload = device_addr.has_key("no_reload_fpga"); if (not _do_not_reload) { - // Load FPGA image if provided via args - const boost::uint16_t pid = boost::lexical_cast<boost::uint16_t>( - device_addr["product"]); - std::string fpga_image; - - //extract the FPGA path for the e300 - switch(e300_eeprom_manager::get_mb_type(pid)) { - case e300_eeprom_manager::USRP_E310_MB: - fpga_image = device_addr.cast<std::string>("fpga", - find_image_path(E310_FPGA_FILE_NAME)); - _idle_image = find_image_path(E310_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(E300_FPGA_IDLE_FILE_NAME); - break; - case e300_eeprom_manager::UNKNOWN: - default: - UHD_MSG(warning) << "Unknown motherboard type, loading e300 image." - << std::endl; - fpga_image = device_addr.cast<std::string>("fpga", - find_image_path(E300_FPGA_FILE_NAME)); - _idle_image = find_image_path(E300_FPGA_IDLE_FILE_NAME); - break; - } + get_e3x0_fpga_images(device_addr, + fpga_image, + _idle_image); common::load_fpga_image(fpga_image); } } @@ -387,18 +394,35 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) // 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); } + _codec_mgr = ad936x_manager::make(_codec_ctrl, fpga::NUM_RADIOS); - UHD_MSG(status) << "Detecting internal GPSDO.... " << std::flush; - if (_xport_path == AXI) { - try { - _gps = gps::ublox::ubx::control::make("/dev/ttyPS1", 9600); - } catch (std::exception &e) { - UHD_MSG(error) << "An error occured making GPSDO control: " << e.what() << std::endl; +#ifdef E300_GPSD + UHD_MSG(status) << "Detecting internal GPSDO " << std::flush; + 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_MSG(error) << "An error occured making GPSDd interface: " << e.what() << std::endl; + } + + 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; + } } - _sensor_manager = e300_sensor_manager::make_local(_gps, _global_regs); + UHD_MSG(status) << (_gps->gps_detected() ? "found" : "not found") << std::endl; } - UHD_MSG(status) << (_sensor_manager->get_gps_found() ? "found" : "not found") << std::endl; +#endif // Verify we can talk to the e300 core control registers ... UHD_MSG(status) << "Initializing core control..." << std::endl; @@ -443,6 +467,15 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) _tree->create<sensor_value_t>(mb_path / "sensors" / name) .publish(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) + .publish(boost::bind(&gpsd_iface::get_sensor, _gps, name)); + } + } +#endif //////////////////////////////////////////////////////////////////// // setup the mboard eeprom @@ -471,28 +504,23 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) for(size_t instance = 0; instance < fpga::NUM_RADIOS; instance++) this->_setup_radio(instance); - _codec_ctrl->data_port_loopback(true); - // Radio 0 loopback through AD9361 - this->_codec_loopback_self_test(_radio_perifs[0].ctrl); + _codec_mgr->loopback_self_test(_radio_perifs[0].ctrl, radio::sr_addr(radio::CODEC_IDLE), radio::RB64_CODEC_READBACK); // Radio 1 loopback through AD9361 - this->_codec_loopback_self_test(_radio_perifs[1].ctrl); - - _codec_ctrl->data_port_loopback(false); + _codec_mgr->loopback_self_test(_radio_perifs[1].ctrl, radio::sr_addr(radio::CODEC_IDLE), radio::RB64_CODEC_READBACK); //////////////////////////////////////////////////////////////////// // internal gpios //////////////////////////////////////////////////////////////////// - gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, TOREG(SR_FP_GPIO), RB32_FP_GPIO); - const std::vector<std::string> gpio_attrs = boost::assign::list_of("CTRL")("DDR")("OUT")("ATR_0X")("ATR_RX")("ATR_TX")("ATR_XX"); - BOOST_FOREACH(const std::string &attr, gpio_attrs) + gpio_core_200::sptr fp_gpio = gpio_core_200::make(_radio_perifs[0].ctrl, radio::sr_addr(radio::FP_GPIO), radio::RB32_FP_GPIO); + BOOST_FOREACH(const gpio_attr_map_t::value_type attr, gpio_attr_map) { - _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr) - .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr, _1)) + _tree->create<boost::uint32_t>(mb_path / "gpio" / "INT0" / attr.second) + .subscribe(boost::bind(&e300_impl::_set_internal_gpio, this, fp_gpio, attr.first, _1)) .set(0); } _tree->create<boost::uint8_t>(mb_path / "gpio" / "INT0" / "READBACK") - .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio, "READBACK")); + .publish(boost::bind(&e300_impl::_get_internal_gpio, this, fp_gpio)); //////////////////////////////////////////////////////////////////// @@ -510,7 +538,11 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) _tree->create<std::string>(mb_path / "time_source" / "value") .subscribe(boost::bind(&e300_impl::_update_time_source, this, _1)) .set(e300::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> >(mb_path / "time_source" / "options").set(time_sources); //setup reference source props _tree->create<std::string>(mb_path / "clock_source" / "value") @@ -575,7 +607,7 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) // init the clock rate to something reasonable _tree->access<double>(mb_path / "tick_rate").set( - device_addr.cast<double>("master_clock_rate", e300::DEFAULT_TICK_RATE)); + 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; @@ -589,41 +621,37 @@ e300_impl::e300_impl(const uhd::device_addr_t &device_addr) } _tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(rx_spec); _tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_spec); - - UHD_MSG(status) << "Initializing time to the internal GPSDO" << std::endl; - const time_t tp = time_t(_sensor_manager->get_sensor("gps_time").to_int()+1); - _tree->access<time_spec_t>(mb_path / "time" / "pps").set(time_spec_t(tp)); - - // wait for time to be actually set - boost::this_thread::sleep(boost::posix_time::seconds(1)); } -boost::uint8_t e300_impl::_get_internal_gpio( - gpio_core_200::sptr gpio, - const std::string &) +boost::uint8_t e300_impl::_get_internal_gpio(gpio_core_200::sptr gpio) { return boost::uint32_t(gpio->read_gpio(dboard_iface::UNIT_RX)); } void e300_impl::_set_internal_gpio( gpio_core_200::sptr gpio, - const std::string &attr, + const gpio_attr_t attr, const boost::uint32_t value) { - if (attr == "CTRL") + switch (attr) + { + case GPIO_CTRL: return gpio->set_pin_ctrl(dboard_iface::UNIT_RX, value); - else if (attr == "DDR") + case GPIO_DDR: return gpio->set_gpio_ddr(dboard_iface::UNIT_RX, value); - else if (attr == "OUT") + case GPIO_OUT: return gpio->set_gpio_out(dboard_iface::UNIT_RX, value); - else if (attr == "ATR_0X") + case GPIO_ATR_0X: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_IDLE, value); - else if (attr == "ATR_RX") + case GPIO_ATR_RX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_RX_ONLY, value); - else if (attr == "ATR_TX") + case GPIO_ATR_TX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_TX_ONLY, value); - else if (attr == "ATR_XX") + case GPIO_ATR_XX: return gpio->set_atr_reg(dboard_iface::UNIT_RX, dboard_iface::ATR_REG_FULL_DUPLEX, value); + default: + UHD_THROW_INVALID_CODE_PATH(); + } } uhd::sensor_value_t e300_impl::_get_fe_pll_lock(const bool is_tx) @@ -665,6 +693,17 @@ void e300_impl::_enforce_tick_rate_limits( % direction )); } + // Minimum rate restriction due to MMCM used in capture interface to AD9361. + // Xilinx Artix-7 FPGA MMCM minimum input frequency is 10 MHz. + const double min_tick_rate = uhd::usrp::e300::MIN_TICK_RATE / ((chan_count <= 1) ? 1 : 2); + if (tick_rate - min_tick_rate < 0.0) + { + throw uhd::value_error(boost::str( + boost::format("current master clock rate (%.6f MHz) set below minimum possible master clock rate (%.6f MHz)") + % (tick_rate/1e6) + % (min_tick_rate/1e6) + )); + } } } @@ -690,8 +729,8 @@ void e300_impl::_register_loopback_self_test(wb_iface::sptr iface) for (size_t i = 0; i < 100; i++) { boost::hash_combine(hash, i); - iface->poke32(TOREG(SR_TEST), boost::uint32_t(hash)); - test_fail = iface->peek32(RB32_TEST) != boost::uint32_t(hash); + iface->poke32(radio::sr_addr(radio::TEST), boost::uint32_t(hash)); + test_fail = iface->peek32(radio::RB32_TEST) != boost::uint32_t(hash); if (test_fail) break; //exit loop on any failure } UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; @@ -721,30 +760,6 @@ std::string e300_impl::_get_version_hash(void) % ((git_hash & 0xF000000) ? "-dirty" : "")); } -void e300_impl::_codec_loopback_self_test(wb_iface::sptr iface) -{ - bool test_fail = false; - UHD_ASSERT_THROW(bool(iface)); - UHD_MSG(status) << "Performing CODEC loopback test... " << std::flush; - size_t hash = size_t(time(NULL)); - for (size_t i = 0; i < 100; i++) - { - boost::hash_combine(hash, i); - const boost::uint32_t word32 = boost::uint32_t(hash) & 0xfff0fff0; - iface->poke32(TOREG(SR_CODEC_IDLE), word32); - iface->peek64(RB64_CODEC_READBACK); //enough idleness for loopback to propagate - const boost::uint64_t rb_word64 = iface->peek64(RB64_CODEC_READBACK); - const boost::uint32_t rb_tx = boost::uint32_t(rb_word64 >> 32); - const boost::uint32_t rb_rx = boost::uint32_t(rb_word64 & 0xffffffff); - test_fail = word32 != rb_tx or word32 != rb_rx; - if (test_fail) break; //exit loop on any failure - } - UHD_MSG(status) << ((test_fail)? " fail" : "pass") << std::endl; - - /* Zero out the idle data. */ - iface->poke32(TOREG(SR_CODEC_IDLE), 0); -} - boost::uint32_t e300_impl::_allocate_sid(const sid_config_t &config) { const boost::uint32_t stream = (config.dst_prefix | (config.router_dst_there << 2)) & 0xff; @@ -799,8 +814,10 @@ void e300_impl::_update_time_source(const std::string &source) UHD_MSG(status) << 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 { @@ -928,6 +945,7 @@ void e300_impl::_setup_radio(const size_t dspno) { radio_perifs_t &perif = _radio_perifs[dspno]; const fs_path mb_path = "/mboards/0"; + std::string slot_name = (dspno == 0) ? "A" : "B"; //////////////////////////////////////////////////////////////////// // crossbar config for ctrl xports @@ -956,137 +974,99 @@ void e300_impl::_setup_radio(const size_t dspno) ctrl_sid, dspno ? "1" : "0"); this->_register_loopback_self_test(perif.ctrl); - perif.atr = gpio_core_200_32wo::make(perif.ctrl, TOREG(SR_GPIO)); + + //////////////////////////////////////////////////////////////////// + // Set up peripherals + //////////////////////////////////////////////////////////////////// + perif.atr = gpio_core_200_32wo::make(perif.ctrl, radio::sr_addr(radio::GPIO)); + perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::RX_FRONT)); + perif.rx_fe->set_dc_offset(rx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); + perif.rx_fe->set_dc_offset_auto(rx_frontend_core_200::DEFAULT_DC_OFFSET_ENABLE); + perif.rx_fe->set_iq_balance(rx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); + perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, radio::sr_addr(radio::TX_FRONT)); + perif.tx_fe->set_dc_offset(tx_frontend_core_200::DEFAULT_DC_OFFSET_VALUE); + perif.tx_fe->set_iq_balance(tx_frontend_core_200::DEFAULT_IQ_BALANCE_VALUE); + perif.framer = rx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_CTRL)); + perif.ddc = rx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::RX_DSP)); + perif.ddc->set_link_rate(10e9/8); //whatever + perif.ddc->set_freq(e300::DEFAULT_DDC_FREQ); + perif.deframer = tx_vita_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_CTRL)); + perif.duc = tx_dsp_core_3000::make(perif.ctrl, radio::sr_addr(radio::TX_DSP)); + perif.duc->set_link_rate(10e9/8); //whatever + perif.duc->set_freq(e300::DEFAULT_DUC_FREQ); + + //////////////////////////////////////////////////////////////////// + // create time control objects + //////////////////////////////////////////////////////////////////// + time_core_3000::readback_bases_type time64_rb_bases; + time64_rb_bases.rb_now = radio::RB64_TIME_NOW; + time64_rb_bases.rb_pps = radio::RB64_TIME_PPS; + perif.time64 = time_core_3000::make(perif.ctrl, radio::sr_addr(radio::TIME), time64_rb_bases); //////////////////////////////////////////////////////////////////// // front end corrections //////////////////////////////////////////////////////////////////// - std::string slot_name = (dspno == 0) ? "A" : "B"; - perif.rx_fe = rx_frontend_core_200::make(perif.ctrl, TOREG(SR_RX_FRONT)); - const fs_path rx_fe_path = mb_path / "rx_frontends" / slot_name; - _tree->create<std::complex<double> >(rx_fe_path / "dc_offset" / "value") - .coerce(boost::bind(&rx_frontend_core_200::set_dc_offset, perif.rx_fe, _1)) - .set(std::complex<double>(0.0, 0.0)); - _tree->create<bool>(rx_fe_path / "dc_offset" / "enable") - .subscribe(boost::bind(&rx_frontend_core_200::set_dc_offset_auto, perif.rx_fe, _1)) - .set(true); - _tree->create<std::complex<double> >(rx_fe_path / "iq_balance" / "value") - .subscribe(boost::bind(&rx_frontend_core_200::set_iq_balance, perif.rx_fe, _1)) - .set(std::complex<double>(0.0, 0.0)); - - perif.tx_fe = tx_frontend_core_200::make(perif.ctrl, TOREG(SR_TX_FRONT)); - const fs_path tx_fe_path = mb_path / "tx_frontends" / slot_name; - _tree->create<std::complex<double> >(tx_fe_path / "dc_offset" / "value") - .coerce(boost::bind(&tx_frontend_core_200::set_dc_offset, perif.tx_fe, _1)) - .set(std::complex<double>(0.0, 0.0)); - _tree->create<std::complex<double> >(tx_fe_path / "iq_balance" / "value") - .subscribe(boost::bind(&tx_frontend_core_200::set_iq_balance, perif.tx_fe, _1)) - .set(std::complex<double>(0.0, 0.0)); + perif.rx_fe->populate_subtree(_tree->subtree(mb_path / "rx_frontends" / slot_name)); + perif.tx_fe->populate_subtree(_tree->subtree(mb_path / "tx_frontends" / slot_name)); //////////////////////////////////////////////////////////////////// - // create rx dsp control objects + // connect rx dsp control objects //////////////////////////////////////////////////////////////////// - perif.framer = rx_vita_core_3000::make(perif.ctrl, TOREG(SR_RX_CTRL)); - perif.ddc = rx_dsp_core_3000::make(perif.ctrl, TOREG(SR_RX_DSP)); - perif.ddc->set_link_rate(10e9/8); //whatever _tree->access<double>(mb_path / "tick_rate") .subscribe(boost::bind(&rx_vita_core_3000::set_tick_rate, perif.framer, _1)) .subscribe(boost::bind(&rx_dsp_core_3000::set_tick_rate, perif.ddc, _1)); const fs_path rx_dsp_path = mb_path / "rx_dsps" / str(boost::format("%u") % dspno); - _tree->create<meta_range_t>(rx_dsp_path / "rate" / "range") - .publish(boost::bind(&rx_dsp_core_3000::get_host_rates, perif.ddc)); - _tree->create<double>(rx_dsp_path / "rate" / "value") - .coerce(boost::bind(&rx_dsp_core_3000::set_host_rate, perif.ddc, _1)) + perif.ddc->populate_subtree(_tree->subtree(rx_dsp_path)); + _tree->access<double>(rx_dsp_path / "rate" / "value") .subscribe(boost::bind(&e300_impl::_update_rx_samp_rate, this, dspno, _1)) - .set(e300::DEFAULT_RX_SAMP_RATE); - _tree->create<double>(rx_dsp_path / "freq" / "value") - .coerce(boost::bind(&rx_dsp_core_3000::set_freq, perif.ddc, _1)) - .set(e300::DEFAULT_DDC_FREQ); - _tree->create<meta_range_t>(rx_dsp_path / "freq" / "range") - .publish(boost::bind(&rx_dsp_core_3000::get_freq_range, perif.ddc)); + ; _tree->create<stream_cmd_t>(rx_dsp_path / "stream_cmd") .subscribe(boost::bind(&rx_vita_core_3000::issue_stream_command, perif.framer, _1)); //////////////////////////////////////////////////////////////////// // create tx dsp control objects //////////////////////////////////////////////////////////////////// - perif.deframer = tx_vita_core_3000::make(perif.ctrl, TOREG(SR_TX_CTRL)); - perif.duc = tx_dsp_core_3000::make(perif.ctrl, TOREG(SR_TX_DSP)); - perif.duc->set_link_rate(10e9/8); //whatever _tree->access<double>(mb_path / "tick_rate") .subscribe(boost::bind(&tx_vita_core_3000::set_tick_rate, perif.deframer, _1)) .subscribe(boost::bind(&tx_dsp_core_3000::set_tick_rate, perif.duc, _1)); const fs_path tx_dsp_path = mb_path / "tx_dsps" / str(boost::format("%u") % dspno); - _tree->create<meta_range_t>(tx_dsp_path / "rate" / "range") - .publish(boost::bind(&tx_dsp_core_3000::get_host_rates, perif.duc)); - _tree->create<double>(tx_dsp_path / "rate" / "value") - .coerce(boost::bind(&tx_dsp_core_3000::set_host_rate, perif.duc, _1)) + perif.duc->populate_subtree(_tree->subtree(tx_dsp_path)); + _tree->access<double>(tx_dsp_path / "rate" / "value") .subscribe(boost::bind(&e300_impl::_update_tx_samp_rate, this, dspno, _1)) - .set(e300::DEFAULT_TX_SAMP_RATE); - _tree->create<double>(tx_dsp_path / "freq" / "value") - .coerce(boost::bind(&tx_dsp_core_3000::set_freq, perif.duc, _1)) - .set(e300::DEFAULT_DUC_FREQ); - _tree->create<meta_range_t>(tx_dsp_path / "freq" / "range") - .publish(boost::bind(&tx_dsp_core_3000::get_freq_range, perif.duc)); - - //////////////////////////////////////////////////////////////////// - // create time control objects - //////////////////////////////////////////////////////////////////// - time_core_3000::readback_bases_type time64_rb_bases; - time64_rb_bases.rb_now = RB64_TIME_NOW; - time64_rb_bases.rb_pps = RB64_TIME_PPS; - perif.time64 = time_core_3000::make(perif.ctrl, TOREG(SR_TIME), time64_rb_bases); + ; //////////////////////////////////////////////////////////////////// // create RF frontend interfacing //////////////////////////////////////////////////////////////////// - static const std::vector<std::string> data_directions = boost::assign::list_of("rx")("tx"); - BOOST_FOREACH(const std::string& direction, data_directions) - { - const std::string key = boost::to_upper_copy(direction) + std::string(((dspno == FE0)? "1" : "2")); + 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(((dspno == FE0)? "1" : "2")); const fs_path rf_fe_path - = mb_path / "dboards" / "A" / (direction + "_frontends") / ((dspno == 0) ? "A" : "B"); + = mb_path / "dboards" / "A" / (x + "_frontends") / ((dspno == 0) ? "A" : "B"); - _tree->create<std::string>(rf_fe_path / "name").set("FE-"+key); - _tree->create<int>(rf_fe_path / "sensors"); //empty TODO - _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked") - .publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, direction == "tx")); - BOOST_FOREACH(const std::string &name, ad9361_ctrl::get_gain_names(key)) - { - _tree->create<meta_range_t>(rf_fe_path / "gains" / name / "range") - .set(ad9361_ctrl::get_gain_range(key)); + // This will connect all the AD936x-specific items + _codec_mgr->populate_frontend_subtree( + _tree->subtree(rf_fe_path), key, dir + ); - _tree->create<double>(rf_fe_path / "gains" / name / "value") - .coerce(boost::bind(&ad9361_ctrl::set_gain, _codec_ctrl, key, _1)) - .set(e300::DEFAULT_FE_GAIN); - } - _tree->create<std::string>(rf_fe_path / "connection").set("IQ"); - _tree->create<bool>(rf_fe_path / "enabled").set(true); - _tree->create<bool>(rf_fe_path / "use_lo_offset").set(false); - _tree->create<double>(rf_fe_path / "bandwidth" / "value") - .coerce(boost::bind(&ad9361_ctrl::set_bw_filter, _codec_ctrl, key, _1)) - .set(e300::DEFAULT_FE_BW); - _tree->create<meta_range_t>(rf_fe_path / "bandwidth" / "range") - .publish(boost::bind(&ad9361_ctrl::get_bw_filter_range, key)); - _tree->create<double>(rf_fe_path / "freq" / "value") - .publish(boost::bind(&ad9361_ctrl::get_freq, _codec_ctrl, key)) - .coerce(boost::bind(&ad9361_ctrl::tune, _codec_ctrl, key, _1)) + // This will connect all the e300_impl-specific items + _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "lo_locked") + .publish(boost::bind(&e300_impl::_get_fe_pll_lock, this, dir == TX_DIRECTION)) + ; + _tree->access<double>(rf_fe_path / "freq" / "value") .subscribe(boost::bind(&e300_impl::_update_fe_lo_freq, this, key, _1)) - .set(e300::DEFAULT_FE_FREQ); - _tree->create<meta_range_t>(rf_fe_path / "freq" / "range") - .publish(boost::bind(&ad9361_ctrl::get_rf_freq_range)); + ; - //setup RX related stuff - if (key[0] == 'R') { + // 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") .subscribe(boost::bind(&e300_impl::_update_antenna_sel, this, dspno, _1)) .set("RX2"); - _tree->create<sensor_value_t>(rf_fe_path / "sensors" / "rssi") - .publish(boost::bind(&ad9361_ctrl::get_rssi, _codec_ctrl, key)); } - if (key[0] == 'T') { + 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").set("TX/RX"); |