diff options
Diffstat (limited to 'host/lib/usrp/b200')
| -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 | 
5 files changed, 253 insertions, 88 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; | 
