diff options
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/usrp/b200/b200_iface.hpp | 29 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_image_loader.cpp | 16 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.cpp | 283 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_impl.hpp | 11 | ||||
-rw-r--r-- | host/lib/usrp/b200/b200_io_impl.cpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.cpp | 5 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_ctrl.hpp | 2 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.cpp | 14 | ||||
-rw-r--r-- | host/lib/usrp/common/ad9361_driver/ad9361_device.h | 2 | ||||
-rw-r--r-- | host/lib/usrp/e300/e300_remote_codec_ctrl.cpp | 5 |
10 files changed, 277 insertions, 92 deletions
diff --git a/host/lib/usrp/b200/b200_iface.hpp b/host/lib/usrp/b200/b200_iface.hpp index 0c7ee6b9e..19ec561fa 100644 --- a/host/lib/usrp/b200/b200_iface.hpp +++ b/host/lib/usrp/b200/b200_iface.hpp @@ -1,5 +1,5 @@ // -// Copyright 2012-2013,2015 Ettus Research LLC +// Copyright 2012-2013 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 @@ -27,40 +27,55 @@ #include <boost/utility.hpp> #include "ad9361_ctrl.hpp" -enum b200_type_t { +enum b200_product_t { B200, - B210 + B210, + B205 }; +// These are actual USB PIDs (not Ettus Product IDs) const static boost::uint16_t B200_VENDOR_ID = 0x2500; const static boost::uint16_t B200_VENDOR_NI_ID = 0x3923; const static boost::uint16_t B200_PRODUCT_ID = 0x0020; +const static boost::uint16_t B205_PRODUCT_ID = 0x0021; const static boost::uint16_t B200_PRODUCT_NI_ID = 0x7813; const static boost::uint16_t B210_PRODUCT_NI_ID = 0x7814; const static boost::uint16_t FX3_VID = 0x04b4; const static boost::uint16_t FX3_DEFAULT_PID = 0x00f3; const static boost::uint16_t FX3_REENUM_PID = 0x00f0; +//! Map the USB PID to the product (only for PIDs that map to a single product) +static const uhd::dict<boost::uint16_t, b200_product_t> B2XX_PID_TO_PRODUCT = boost::assign::map_list_of + (B200_PRODUCT_NI_ID, B200) + (B210_PRODUCT_NI_ID, B210) + (B205_PRODUCT_ID, B205) +; + static const std::string B200_FW_FILE_NAME = "usrp_b200_fw.hex"; -//! Map the product ID (in the EEPROM) to a device type -static const uhd::dict<boost::uint16_t, b200_type_t> B2X0_PRODUCT_ID = boost::assign::map_list_of +//! Map the EEPROM product ID codes to the product +static const uhd::dict<boost::uint16_t, b200_product_t> B2XX_PRODUCT_ID = boost::assign::map_list_of (0x0001, B200) (0x7737, B200) (B200_PRODUCT_NI_ID, B200) (0x0002, B210) (0x7738, B210) (B210_PRODUCT_NI_ID, B210) + (0x0003, B205) + (0x7739, B205) ; -static const uhd::dict<b200_type_t, std::string> B2X0_STR_NAMES = boost::assign::map_list_of + +static const uhd::dict<b200_product_t, std::string> B2XX_STR_NAMES = boost::assign::map_list_of (B200, "B200") (B210, "B210") + (B205, "B200mini") ; -static const uhd::dict<b200_type_t, std::string> B2X0_FPGA_FILE_NAME = boost::assign::map_list_of +static const uhd::dict<b200_product_t, std::string> B2XX_FPGA_FILE_NAME = boost::assign::map_list_of (B200, "usrp_b200_fpga.bin") (B210, "usrp_b210_fpga.bin") + (B205, "usrp_b200mini_fpga.bin") ; diff --git a/host/lib/usrp/b200/b200_image_loader.cpp b/host/lib/usrp/b200/b200_image_loader.cpp index 9eaeeff63..e8fb8afea 100644 --- a/host/lib/usrp/b200/b200_image_loader.cpp +++ b/host/lib/usrp/b200/b200_image_loader.cpp @@ -35,8 +35,8 @@ using namespace uhd::transport; namespace uhd{ -static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t &image_loader_args, - mboard_eeprom_t &mb_eeprom, +static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t& image_loader_args, + mboard_eeprom_t &mb_eeprom, usb_device_handle::sptr& handle, bool user_specified){ std::vector<usb_device_handle::sptr> dev_handles = get_b200_device_handles(image_loader_args.args); @@ -67,6 +67,7 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t & // At this point, we should have a single B2XX if(applicable_dev_handles.size() == 1){ mb_eeprom = eeprom; + handle = applicable_dev_handles[0]; return iface; } else if(applicable_dev_handles.size() > 1){ @@ -76,7 +77,7 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t & BOOST_FOREACH(usb_device_handle::sptr dev_handle, applicable_dev_handles){ eeprom = mboard_eeprom_t(*b200_iface::make(usb_control::make(dev_handle,0)), "B200"); err_msg += str(boost::format(" * %s (serial=%s)\n") - % B2X0_STR_NAMES.get(get_b200_type(mb_eeprom), "B2XX") + % B2XX_STR_NAMES.get(get_b200_product(dev_handle, mb_eeprom), "B2XX") % mb_eeprom.get("serial")); } @@ -101,7 +102,8 @@ static bool b200_image_loader(const image_loader::image_loader_args_t &image_loa // See if a B2x0 with the given args is found mboard_eeprom_t mb_eeprom; - b200_iface::sptr iface = get_b200_iface(image_loader_args, mb_eeprom, user_specified); + usb_device_handle::sptr handle; + b200_iface::sptr iface = get_b200_iface(image_loader_args, mb_eeprom, handle, user_specified); if(!iface) return false; // No initialized B2x0 found std::string fpga_path; @@ -112,7 +114,7 @@ static bool b200_image_loader(const image_loader::image_loader_args_t &image_loa * filename for us to use. */ std::string product = mb_eeprom.get("product"); - if(not B2X0_PRODUCT_ID.has_key(boost::lexical_cast<boost::uint16_t>(product))){ + if(not B2XX_PRODUCT_ID.has_key(boost::lexical_cast<boost::uint16_t>(product))){ if(user_specified){ // The user specified a bad device but expects us to know what it is throw uhd::runtime_error("Could not determine model. You must manually specify an FPGA image filename."); @@ -122,13 +124,13 @@ static bool b200_image_loader(const image_loader::image_loader_args_t &image_loa } } else{ - fpga_path = find_image_path(B2X0_FPGA_FILE_NAME.get(get_b200_type(mb_eeprom))); + fpga_path = find_image_path(B2XX_FPGA_FILE_NAME.get(get_b200_product(handle, mb_eeprom))); } } else fpga_path = image_loader_args.fpga_path; std::cout << boost::format("Unit: USRP %s (%s)") - % B2X0_STR_NAMES.get(get_b200_type(mb_eeprom), "B2XX") + % B2XX_STR_NAMES.get(get_b200_product(handle, mb_eeprom), "B2XX") % mb_eeprom.get("serial") << std::endl; diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index f9e7eacfc..6bd49e013 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -45,14 +45,15 @@ using namespace uhd::transport; static const boost::posix_time::milliseconds REENUMERATION_TIMEOUT_MS(3000); +// B200 + B210: class b200_ad9361_client_t : public ad9361_params { public: ~b200_ad9361_client_t() {} double get_band_edge(frequency_band_t band) { switch (band) { - case AD9361_RX_BAND0: return 2.2e9; - case AD9361_RX_BAND1: return 4.0e9; - case AD9361_TX_BAND0: return 2.5e9; + case AD9361_RX_BAND0: return 2.2e9; // Port C + case AD9361_RX_BAND1: return 4.0e9; // Port B + case AD9361_TX_BAND0: return 2.5e9; // Port B default: return 0; } } @@ -72,25 +73,77 @@ public: } }; +// B205 +class b205_ad9361_client_t : public ad9361_params { +public: + ~b205_ad9361_client_t() {} + double get_band_edge(frequency_band_t band) { + switch (band) { + case AD9361_RX_BAND0: return 0; // Set these all to + case AD9361_RX_BAND1: return 0; // zero, so RF port A + case AD9361_TX_BAND0: return 0; // is used all the time + default: return 0; // On both Rx and Tx + } + } + clocking_mode_t get_clocking_mode() { + return 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 = 0x6; + delays.tx_clk_delay = 0; + delays.tx_data_delay = 0xF; + return delays; + } +}; + +/*********************************************************************** + * Helpers + **********************************************************************/ +std::string check_option_valid( + const std::string &name, + const std::vector<std::string> &valid_options, + const std::string &option +) { + if (std::find(valid_options.begin(), valid_options.end(), option) == valid_options.end()) { + throw uhd::runtime_error(str( + boost::format("Invalid option chosen for: %s") + % name + )); + } + + return option; +} + /*********************************************************************** * Discovery **********************************************************************/ //! Look up the type of B-Series device we're currently running. -// If the product ID stored in mb_eeprom is invalid, throws a -// uhd::runtime_error. -b200_type_t get_b200_type(const mboard_eeprom_t &mb_eeprom) +// Throws a uhd::runtime_error if the USB PID and the product ID stored +// in the MB EEPROM are invalid, +b200_product_t get_b200_product(const usb_device_handle::sptr& handle, const mboard_eeprom_t &mb_eeprom) { + // Try USB PID first + boost::uint16_t product_id = handle->get_product_id(); + if (B2XX_PID_TO_PRODUCT.has_key(product_id)) + return B2XX_PID_TO_PRODUCT[product_id]; + + // Try EEPROM product ID code second if (mb_eeprom["product"].empty()) { throw uhd::runtime_error("B200: Missing product ID on EEPROM."); } - boost::uint16_t product_id = boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]); - if (not B2X0_PRODUCT_ID.has_key(product_id)) { + product_id = boost::lexical_cast<boost::uint16_t>(mb_eeprom["product"]); + if (not B2XX_PRODUCT_ID.has_key(product_id)) { throw uhd::runtime_error(str( boost::format("B200 unknown product code: 0x%04x") % product_id )); } - return B2X0_PRODUCT_ID[product_id]; + return B2XX_PRODUCT_ID[product_id]; } std::vector<usb_device_handle::sptr> get_b200_device_handles(const device_addr_t &hint) @@ -173,9 +226,10 @@ static device_addrs_t b200_find(const device_addr_t &hint) new_addr["serial"] = handle->get_serial(); try { // Turn the 16-Bit product ID into a string representation - new_addr["product"] = B2X0_STR_NAMES[get_b200_type(mb_eeprom)]; + new_addr["product"] = B2XX_STR_NAMES[get_b200_product(handle, mb_eeprom)]; } catch (const uhd::runtime_error &e) { // No problem if this fails -- this is just device discovery, after all. + new_addr["product"] = "B2??"; } //this is a found b200 when the hint serial and name match or blank @@ -225,7 +279,9 @@ UHD_STATIC_BLOCK(register_b200_device) * Structors **********************************************************************/ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::sptr &handle) : + _product(B200), // Some safe value _revision(0), + _time_source(UNKNOWN), _tick_rate(0.0) // Forces a clock initialization at startup { _tree = property_tree::make(); @@ -260,9 +316,10 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s // Search for all supported PIDs limited to specified VID if only VID specified else if (specified_vid) { - vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_ID)); - vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B200_PRODUCT_NI_ID)); - vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid,B210_PRODUCT_NI_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B200_PRODUCT_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B205_PRODUCT_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B200_PRODUCT_NI_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(vid, B210_PRODUCT_NI_ID)); } // Search for all supported VIDs limited to specified PID if only PID specified else if (specified_pid) @@ -273,9 +330,10 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s // Search for all supported devices if neither VID nor PID specified else { - vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID,B200_PRODUCT_ID)); - vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B200_PRODUCT_NI_ID)); - vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID,B210_PRODUCT_NI_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B205_PRODUCT_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID)); + vid_pid_pair_list.push_back(usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID)); } std::vector<usb_device_handle::sptr> device_list = usb_device_handle::get_device_list(vid_pid_pair_list); @@ -309,9 +367,9 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s std::string product_name; try { // This will throw if the product ID is invalid: - _b200_type = get_b200_type(mb_eeprom); - default_file_name = B2X0_FPGA_FILE_NAME.get(_b200_type); - product_name = B2X0_STR_NAMES.get(_b200_type); + _product = get_b200_product(handle, mb_eeprom); + default_file_name = B2XX_FPGA_FILE_NAME.get(_product); + product_name = B2XX_STR_NAMES.get(_product); } catch (const uhd::runtime_error &e) { // The only reason we may let this pass is if the user specified // the FPGA file name: @@ -320,12 +378,15 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s } // In this case, we must provide a default product name: product_name = "B200?"; - _b200_type = B200; } if (not mb_eeprom["revision"].empty()) { _revision = boost::lexical_cast<size_t>(mb_eeprom["revision"]); } + UHD_MSG(status) << "Detected Device: " << B2XX_STR_NAMES[_product] << std::endl; + + _gpsdo_capable = (_product != B205); + //////////////////////////////////////////////////////////////////// // Set up frontend mapping //////////////////////////////////////////////////////////////////// @@ -343,7 +404,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s _fe2 = 0; _gpio_state.swap_atr = 1; // Unswapped setup: - if (_b200_type == B200 and _revision >= 5) { + if (_product == B205 or (_product == B200 and _revision >= 5)) { _fe1 = 0; //map radio0 to FE1 _fe2 = 1; //map radio1 to FE2 _gpio_state.swap_atr = 0; // ATRs for radio0 are mapped to FE1 @@ -411,34 +472,37 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s //////////////////////////////////////////////////////////////////// // Create the GPSDO control //////////////////////////////////////////////////////////////////// - _async_task_data->gpsdo_uart = b200_uart::make(_ctrl_transport, B200_TX_GPS_UART_SID); - _async_task_data->gpsdo_uart->set_baud_divider(B200_BUS_CLOCK_RATE/115200); - _async_task_data->gpsdo_uart->write_uart("\n"); //cause the baud and response to be setup - boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for a little propagation - - if ((_local_ctrl->peek32(RB32_CORE_STATUS) & 0xff) != B200_GPSDO_ST_NONE) + if (_gpsdo_capable) { - UHD_MSG(status) << "Detecting internal GPSDO.... " << std::flush; - try - { - _gps = gps_ctrl::make(_async_task_data->gpsdo_uart); - } - catch(std::exception &e) - { - UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl; - } - if (_gps and _gps->gps_detected()) + _async_task_data->gpsdo_uart = b200_uart::make(_ctrl_transport, B200_TX_GPS_UART_SID); + _async_task_data->gpsdo_uart->set_baud_divider(B200_BUS_CLOCK_RATE/115200); + _async_task_data->gpsdo_uart->write_uart("\n"); //cause the baud and response to be setup + boost::this_thread::sleep(boost::posix_time::seconds(1)); //allow for a little propagation + + if ((_local_ctrl->peek32(RB32_CORE_STATUS) & 0xff) != B200_GPSDO_ST_NONE) { - //UHD_MSG(status) << "found" << std::endl; - BOOST_FOREACH(const std::string &name, _gps->get_sensors()) + UHD_MSG(status) << "Detecting internal GPSDO.... " << std::flush; + try { - _tree->create<sensor_value_t>(mb_path / "sensors" / name) - .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name)); + _gps = gps_ctrl::make(_async_task_data->gpsdo_uart); + } + catch(std::exception &e) + { + UHD_MSG(error) << "An error occurred making GPSDO control: " << e.what() << std::endl; + } + if (_gps and _gps->gps_detected()) + { + //UHD_MSG(status) << "found" << std::endl; + BOOST_FOREACH(const std::string &name, _gps->get_sensors()) + { + _tree->create<sensor_value_t>(mb_path / "sensors" / name) + .publish(boost::bind(&gps_ctrl::get_sensor, _gps, name)); + } + } + else + { + _local_ctrl->poke32(TOREG(SR_CORE_GPSDO_ST), B200_GPSDO_ST_NONE); } - } - else - { - _local_ctrl->poke32(TOREG(SR_CORE_GPSDO_ST), B200_GPSDO_ST_NONE); } } @@ -447,7 +511,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s //////////////////////////////////////////////////////////////////// _tree->create<std::string>("/name").set("B-Series Device"); _tree->create<std::string>(mb_path / "name").set(product_name); - _tree->create<std::string>(mb_path / "codename").set("Sasquatch"); + _tree->create<std::string>(mb_path / "codename").set((_product == B205) ? "Pixie" : "Sasquatch"); //////////////////////////////////////////////////////////////////// // Create data transport @@ -475,13 +539,20 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s // create time and clock control objects //////////////////////////////////////////////////////////////////// _spi_iface = b200_local_spi_core::make(_local_ctrl); - _adf4001_iface = boost::make_shared<b200_ref_pll_ctrl>(_spi_iface); + if (_product != B205) { + _adf4001_iface = boost::make_shared<b200_ref_pll_ctrl>(_spi_iface); + } //////////////////////////////////////////////////////////////////// // Init codec - turns on clocks //////////////////////////////////////////////////////////////////// UHD_MSG(status) << "Initialize CODEC control..." << std::endl; - ad9361_params::sptr client_settings = boost::make_shared<b200_ad9361_client_t>(); + ad9361_params::sptr client_settings; + if (_product == B205) { + client_settings = boost::make_shared<b205_ad9361_client_t>(); + } else { + client_settings = boost::make_shared<b200_ad9361_client_t>(); + } _codec_ctrl = ad9361_ctrl::make_spi(client_settings, _spi_iface, AD9361_SLAVENO); this->reset_codec_dcm(); @@ -564,15 +635,23 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s } //setup time source props + static const std::vector<std::string> time_sources = (_gpsdo_capable) ? + boost::assign::list_of("none")("internal")("external")("gpsdo") : + boost::assign::list_of("none")("internal")("external") ; + _tree->create<std::vector<std::string> >(mb_path / "time_source" / "options") + .set(time_sources); _tree->create<std::string>(mb_path / "time_source" / "value") + .coerce(boost::bind(&check_option_valid, "time source", time_sources, _1)) .subscribe(boost::bind(&b200_impl::update_time_source, this, _1)); - static const std::vector<std::string> time_sources = boost::assign::list_of("none")("internal")("external")("gpsdo"); - _tree->create<std::vector<std::string> >(mb_path / "time_source" / "options").set(time_sources); //setup reference source props + static const std::vector<std::string> clock_sources = (_gpsdo_capable) ? + boost::assign::list_of("internal")("external")("gpsdo") : + boost::assign::list_of("internal")("external") ; + _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options") + .set(clock_sources); _tree->create<std::string>(mb_path / "clock_source" / "value") + .coerce(boost::bind(&check_option_valid, "clock source", clock_sources, _1)) .subscribe(boost::bind(&b200_impl::update_clock_source, this, _1)); - static const std::vector<std::string> clock_sources = boost::assign::list_of("internal")("external")("gpsdo"); - _tree->create<std::vector<std::string> >(mb_path / "clock_source" / "options").set(clock_sources); //////////////////////////////////////////////////////////////////// // front panel gpio @@ -870,12 +949,14 @@ void b200_impl::check_fpga_compat(void) if (signature != 0xACE0BA5E) throw uhd::runtime_error( "b200::check_fpga_compat signature register readback failed"); - if (compat_major != B200_FPGA_COMPAT_NUM){ + const boost::uint16_t expected = (_product == B205 ? B205_FPGA_COMPAT_NUM : B200_FPGA_COMPAT_NUM); + if (compat_major != expected) + { throw uhd::runtime_error(str(boost::format( "Expected FPGA compatibility number %d, but got %d:\n" "The FPGA build is not compatible with the host code build.\n" "%s" - ) % int(B200_FPGA_COMPAT_NUM) % compat_major % print_utility_error("uhd_images_downloader.py"))); + ) % int(expected) % compat_major % print_utility_error("uhd_images_downloader.py"))); } _tree->create<std::string>("/mboards/0/fpga_version").set(str(boost::format("%u.%u") % compat_major % compat_minor)); @@ -913,35 +994,92 @@ void b200_impl::set_fp_gpio(gpio_core_200::sptr gpio, const gpio_attr_t attr, co void b200_impl::update_clock_source(const std::string &source) { - // present the PLL with a valid 10 MHz signal before switching its reference - _gpio_state.ref_sel = (source == "gpsdo")? 1 : 0; - this->update_gpio_state(); + // For B205, ref_sel selects whether or not to lock to the external clock source + if (_product == B205) + { + if (source == "external" and _time_source == EXTERNAL) + { + throw uhd::value_error("external reference cannot be both a clock source and a time source"); + } - if (source == "internal"){ - _adf4001_iface->set_lock_to_ext_ref(false); + if (source == "internal") + { + if (_gpio_state.ref_sel != 0) + { + _gpio_state.ref_sel = 0; + this->update_gpio_state(); + } + } + else if (source == "external") + { + if (_gpio_state.ref_sel != 1) + { + _gpio_state.ref_sel = 1; + this->update_gpio_state(); + } + } + else + { + throw uhd::key_error("update_clock_source: unknown source: " + source); + } + return; } - else if ((source == "external") - or (source == "gpsdo")){ + // For all other devices, ref_sel selects the external or gpsdo clock source + // and the ADF4001 selects whether to lock to it or not + if (source == "internal") + { + _adf4001_iface->set_lock_to_ext_ref(false); + } + else if (source == "external") + { + if (_gpio_state.ref_sel != 0) + { + _gpio_state.ref_sel = 0; + this->update_gpio_state(); + } _adf4001_iface->set_lock_to_ext_ref(true); - } else { + } + else if (_gps and source == "gpsdo") + { + if (_gpio_state.ref_sel != 1) + { + _gpio_state.ref_sel = 1; + this->update_gpio_state(); + } + _adf4001_iface->set_lock_to_ext_ref(true); + } + else + { throw uhd::key_error("update_clock_source: unknown source: " + source); } } void b200_impl::update_time_source(const std::string &source) { - boost::uint32_t value = 0; + if (_product == B205 and source == "external" and _gpio_state.ref_sel == 1) + { + throw uhd::value_error("external reference cannot be both a time source and a clock source"); + } + + // We assume source is valid for this device (if it's gone through + // the prop three, then it definitely is thanks to our coercer) + time_source_t value; if (source == "none") - value = 3; + value = NONE; else if (source == "internal") - value = 2; + value = INTERNAL; else if (source == "external") - value = 1; - else if (source == "gpsdo") - value = 0; - else throw uhd::key_error("update_time_source: unknown source: " + source); - _local_ctrl->poke32(TOREG(SR_CORE_PPS_SEL), value); + value = EXTERNAL; + else if (_gps and source == "gpsdo") + value = GPSDO; + else + throw uhd::key_error("update_time_source: unknown source: " + source); + if (_time_source != value) + { + _local_ctrl->poke32(TOREG(SR_CORE_PPS_SEL), value); + _time_source = value; + } } /*********************************************************************** @@ -950,6 +1088,11 @@ void b200_impl::update_time_source(const std::string &source) void b200_impl::update_bandsel(const std::string& which, double freq) { + // B205 does not have bandsels + if (_product == B205) { + return; + } + if(which[0] == 'R') { if(freq < 2.2e9) { _gpio_state.rx_bandsel_a = 0; diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 8f527221f..b291f8e5c 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -50,6 +50,7 @@ static const boost::uint8_t B200_FW_COMPAT_NUM_MAJOR = 8; static const boost::uint8_t B200_FW_COMPAT_NUM_MINOR = 0; static const boost::uint16_t B200_FPGA_COMPAT_NUM = 10; +static const boost::uint16_t B205_FPGA_COMPAT_NUM = 1; static const double B200_BUS_CLOCK_RATE = 100e6; static const boost::uint32_t B200_GPSDO_ST_NONE = 0x83; static const size_t B200_MAX_RATE_USB2 = 53248000; // bytes/s @@ -94,11 +95,12 @@ static const unsigned char B200_USB_DATA_SEND_ENDPOINT = 2; static std::vector<uhd::transport::usb_device_handle::vid_pid_pair_t> b200_vid_pid_pairs = boost::assign::list_of (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B200_PRODUCT_ID)) + (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_ID, B205_PRODUCT_ID)) (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B200_PRODUCT_NI_ID)) (uhd::transport::usb_device_handle::vid_pid_pair_t(B200_VENDOR_NI_ID, B210_PRODUCT_NI_ID)) ; -b200_type_t get_b200_type(const uhd::usrp::mboard_eeprom_t &mb_eeprom); +b200_product_t get_b200_product(const uhd::transport::usb_device_handle::sptr& handle, const uhd::usrp::mboard_eeprom_t &mb_eeprom); std::vector<uhd::transport::usb_device_handle::sptr> get_b200_device_handles(const uhd::device_addr_t &hint); //! Implementation guts @@ -122,8 +124,9 @@ public: void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = ""); private: - b200_type_t _b200_type; - size_t _revision; + b200_product_t _product; + size_t _revision; + bool _gpsdo_capable; //controllers b200_iface::sptr _iface; @@ -216,6 +219,8 @@ private: } } _gpio_state; + enum time_source_t {GPSDO=0,EXTERNAL=1,INTERNAL=2,NONE=3,UNKNOWN=4} _time_source; + void update_gpio_state(void); void reset_codec_dcm(void); diff --git a/host/lib/usrp/b200/b200_io_impl.cpp b/host/lib/usrp/b200/b200_io_impl.cpp index 20807bdd4..4aa1a46af 100644 --- a/host/lib/usrp/b200/b200_io_impl.cpp +++ b/host/lib/usrp/b200/b200_io_impl.cpp @@ -228,7 +228,7 @@ uhd::usrp::subdev_spec_t b200_impl::coerce_subdev_spec(const uhd::usrp::subdev_s // // Any other spec is probably illegal and will be caught by // validate_subdev_spec(). - if (spec.size() and _b200_type == B200 and spec[0].sd_name == "B") { + if (spec.size() and (_product == B200 or _product == B205) and spec[0].sd_name == "B") { spec[0].sd_name = "A"; } return spec; diff --git a/host/lib/usrp/common/ad9361_ctrl.cpp b/host/lib/usrp/common/ad9361_ctrl.cpp index 2d9f297b3..54f0fcdbf 100644 --- a/host/lib/usrp/common/ad9361_ctrl.cpp +++ b/host/lib/usrp/common/ad9361_ctrl.cpp @@ -251,6 +251,11 @@ public: _device.set_filter(direction, chain, filter_name, filter); } + void output_digital_test_tone(bool enb) + { + _device.digital_test_tone(enb); + } + private: static ad9361_device_t::direction_t _get_direction_from_antenna(const std::string& antenna) { diff --git a/host/lib/usrp/common/ad9361_ctrl.hpp b/host/lib/usrp/common/ad9361_ctrl.hpp index 044265422..5c438ee9c 100644 --- a/host/lib/usrp/common/ad9361_ctrl.hpp +++ b/host/lib/usrp/common/ad9361_ctrl.hpp @@ -154,6 +154,8 @@ public: //! Write back a filter virtual void set_filter(const std::string &which, const std::string &filter_name, const filter_info_base::sptr) = 0; + + virtual void output_digital_test_tone(bool enb) = 0; }; }} diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp index c3bc2d32b..0a8a61575 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.cpp @@ -1286,16 +1286,16 @@ double ad9361_device_t::_tune_helper(direction_t direction, const double value) /* Set band-specific settings. */ if (value < _client_params->get_band_edge(AD9361_RX_BAND0)) { - _regs.inputsel = (_regs.inputsel & 0xC0) | 0x30; + _regs.inputsel = (_regs.inputsel & 0xC0) | 0x30; // Port C, balanced } else if ((value >= _client_params->get_band_edge(AD9361_RX_BAND0)) && (value < _client_params->get_band_edge(AD9361_RX_BAND1))) { - _regs.inputsel = (_regs.inputsel & 0xC0) | 0x0C; + _regs.inputsel = (_regs.inputsel & 0xC0) | 0x0C; // Port B, balanced } else if ((value >= _client_params->get_band_edge(AD9361_RX_BAND1)) && (value <= 6e9)) { - _regs.inputsel = (_regs.inputsel & 0xC0) | 0x03; + _regs.inputsel = (_regs.inputsel & 0xC0) | 0x03; // Port A, balanced } else { throw uhd::runtime_error("[ad9361_device_t] [_tune_helper] INVALID_CODE_PATH"); } @@ -2127,7 +2127,7 @@ double ad9361_device_t::set_gain(direction_t direction, chain_t chain, const dou } } -void ad9361_device_t::output_test_tone() +void ad9361_device_t::output_test_tone() // On RF side! { boost::lock_guard<boost::recursive_mutex> lock(_mutex); /* Output a 480 kHz tone at 800 MHz */ @@ -2137,6 +2137,12 @@ void ad9361_device_t::output_test_tone() _io_iface->poke8(0x3FE, 0x3F); } +void ad9361_device_t::digital_test_tone(bool enb) // Digital output +{ + boost::lock_guard<boost::recursive_mutex> lock(_mutex); + _io_iface->poke8(0x3F4, 0x02 | (enb ? 0x01 : 0x00)); +} + void ad9361_device_t::data_port_loopback(const bool loopback_enabled) { boost::lock_guard<boost::recursive_mutex> lock(_mutex); diff --git a/host/lib/usrp/common/ad9361_driver/ad9361_device.h b/host/lib/usrp/common/ad9361_driver/ad9361_device.h index efd0f017c..66bc2e8b9 100644 --- a/host/lib/usrp/common/ad9361_driver/ad9361_device.h +++ b/host/lib/usrp/common/ad9361_driver/ad9361_device.h @@ -115,6 +115,8 @@ public: /* Make AD9361 output its test tone. */ void output_test_tone(); + void digital_test_tone(bool enb); // Digital output + /* Turn on/off AD9361's TX port --> RX port loopback. */ void data_port_loopback(const bool loopback_enabled); diff --git a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp index 1e0895393..be98f4027 100644 --- a/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp +++ b/host/lib/usrp/e300/e300_remote_codec_ctrl.cpp @@ -242,6 +242,11 @@ public: UHD_MSG(warning) << "Attempting to set filter on E300 in network mode." << std::endl; } + void output_digital_test_tone(bool enb) + { + UHD_THROW_INVALID_CODE_PATH(); + } + private: void _transact() { { |