diff options
Diffstat (limited to 'host')
34 files changed, 1026 insertions, 935 deletions
diff --git a/host/include/uhd/usrp/mboard_eeprom.hpp b/host/include/uhd/usrp/mboard_eeprom.hpp index f064e9956..270cde1a2 100644 --- a/host/include/uhd/usrp/mboard_eeprom.hpp +++ b/host/include/uhd/usrp/mboard_eeprom.hpp @@ -1,5 +1,6 @@  //  // Copyright 2010-2012 Ettus Research LLC +// Copyright 2017 Ettus Research (National Instruments Corp.)  //  // 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 @@ -18,41 +19,24 @@  #ifndef INCLUDED_UHD_USRP_MBOARD_EEPROM_HPP  #define INCLUDED_UHD_USRP_MBOARD_EEPROM_HPP -#include <uhd/config.hpp>  #include <uhd/types/dict.hpp> -#include <uhd/types/serial.hpp>  #include <string>  namespace uhd{ namespace usrp{ -    /*! -     * The motherboard EEPROM object: -     * Knows how to read and write the EEPROM for various USRPs. -     * The class inherits from a string, string dictionary. -     * Use the dictionary interface to get and set values. -     * Commit to the EEPROM to save changed settings. +    /*!  The motherboard EEPROM object. +     * +     * The specific implementation knows how to read and write the EEPROM for +     * various USRPs. By itself, this class is nothing but a thin wrapper +     * around a string -> string dictionary. +     * +     * Note that writing to an object of type mboard_eeprom_t does not actually +     * write to the EEPROM. Devices have their own APIs to read/write from the +     * EEPROM chips themselves. Most devices will write the EEPROM itself when +     * the according property is updated.       */ -    struct UHD_API mboard_eeprom_t : uhd::dict<std::string, std::string>{ +    using mboard_eeprom_t = uhd::dict<std::string, std::string>; -        //! Make a new empty mboard eeprom -        mboard_eeprom_t(void); - -        /*! -         * Make a new mboard EEPROM handler. -         * \param iface the interface to i2c -         * \param which which EEPROM map to use -         */ -        mboard_eeprom_t(i2c_iface &iface, const std::string &which); - -        /*! -         * Write the contents of this object to the EEPROM. -         * \param iface the interface to i2c -         * \param which which EEPROM map to use -         */ -        void commit(i2c_iface &iface, const std::string &which) const; - -    }; - -}} //namespace +}} // namespace uhd::usrp  #endif /* INCLUDED_UHD_USRP_MBOARD_EEPROM_HPP */ diff --git a/host/lib/usrp/CMakeLists.txt b/host/lib/usrp/CMakeLists.txt index f769417d9..44b1b7c43 100644 --- a/host/lib/usrp/CMakeLists.txt +++ b/host/lib/usrp/CMakeLists.txt @@ -27,7 +27,6 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/dboard_manager.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/gps_ctrl.cpp -    ${CMAKE_CURRENT_SOURCE_DIR}/mboard_eeprom.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/multi_usrp.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/subdev_spec.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/fe_connection.cpp diff --git a/host/lib/usrp/b100/CMakeLists.txt b/host/lib/usrp/b100/CMakeLists.txt index 66129458c..93177fce3 100644 --- a/host/lib/usrp/b100/CMakeLists.txt +++ b/host/lib/usrp/b100/CMakeLists.txt @@ -29,6 +29,7 @@ IF(ENABLE_B100)          ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/mb_eeprom.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usb_zero_copy_wrapper.cpp      )  ENDIF(ENABLE_B100) diff --git a/host/lib/usrp/b100/b100_impl.cpp b/host/lib/usrp/b100/b100_impl.cpp index 27af43c48..110c5ff87 100644 --- a/host/lib/usrp/b100/b100_impl.cpp +++ b/host/lib/usrp/b100/b100_impl.cpp @@ -108,7 +108,8 @@ static device_addrs_t b100_find(const device_addr_t &hint)              catch(const uhd::exception &){continue;} //ignore claimed              fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control); -            const mboard_eeprom_t mb_eeprom = mboard_eeprom_t(*fx2_ctrl, B100_EEPROM_MAP_KEY); +            const mboard_eeprom_t mb_eeprom = +                b100_impl::get_mb_eeprom(fx2_ctrl);              device_addr_t new_addr;              new_addr["type"] = "b100";              new_addr["name"] = mb_eeprom["name"]; @@ -283,7 +284,7 @@ b100_impl::b100_impl(const device_addr_t &device_addr){      ////////////////////////////////////////////////////////////////////      // setup the mboard eeprom      //////////////////////////////////////////////////////////////////// -    const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, B100_EEPROM_MAP_KEY); +    const mboard_eeprom_t mb_eeprom = this->get_mb_eeprom(_fx2_ctrl);      _tree->create<mboard_eeprom_t>(mb_path / "eeprom")          .set(mb_eeprom)          .add_coerced_subscriber(boost::bind(&b100_impl::set_mb_eeprom, this, _1)); @@ -561,10 +562,6 @@ double b100_impl::update_rx_codec_gain(const double gain){      return _codec_ctrl->get_rx_pga_gain('A');  } -void b100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){ -    mb_eeprom.commit(*_fx2_ctrl, B100_EEPROM_MAP_KEY); -} -  void b100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){      if (type == "rx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_RX_A);      if (type == "tx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_A); diff --git a/host/lib/usrp/b100/b100_impl.hpp b/host/lib/usrp/b100/b100_impl.hpp index ba4b3cd90..4faf69b64 100644 --- a/host/lib/usrp/b100/b100_impl.hpp +++ b/host/lib/usrp/b100/b100_impl.hpp @@ -53,7 +53,6 @@ static const uint32_t B100_TX_ASYNC_SID = 10;  static const uint32_t B100_CTRL_MSG_SID = 20;  static const double          B100_DEFAULT_TICK_RATE = 64e6;  static const size_t          B100_MAX_PKT_BYTE_LIMIT = 2048; -static const std::string     B100_EEPROM_MAP_KEY = "B100";  static const size_t          B100_MAX_RATE_USB2  =  32000000; // bytes/s  #define I2C_ADDR_TX_A       (I2C_DEV_EEPROM | 0x4) @@ -105,6 +104,8 @@ public:      uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args);      bool recv_async_msg(uhd::async_metadata_t &, double); +    static uhd::usrp::mboard_eeprom_t get_mb_eeprom(uhd::i2c_iface::sptr); +  private:      //controllers      fifo_ctrl_excelsior::sptr _fifo_ctrl; diff --git a/host/lib/usrp/b100/mb_eeprom.cpp b/host/lib/usrp/b100/mb_eeprom.cpp new file mode 100644 index 000000000..be7137b7b --- /dev/null +++ b/host/lib/usrp/b100/mb_eeprom.cpp @@ -0,0 +1,91 @@ +// +// Copyright 2017 Ettus Research (National Instruments Corp.) +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "b100_impl.hpp" +#include "eeprom_utils.hpp" +#include <uhd/usrp/mboard_eeprom.hpp> + +namespace { +    const uint8_t B100_EEPROM_ADDR = 0x50; + +    //use char array so we dont need to attribute packed +    struct b100_eeprom_map{ +        unsigned char _r[220]; +        unsigned char revision[2]; +        unsigned char product[2]; +        unsigned char name[NAME_MAX_LEN]; +        unsigned char serial[SERIAL_LEN]; +    }; +} + +using namespace uhd; +using uhd::usrp::mboard_eeprom_t; + +mboard_eeprom_t b100_impl::get_mb_eeprom(uhd::i2c_iface::sptr iface) +{ +    mboard_eeprom_t mb_eeprom; + +    //extract the revision number +    mb_eeprom["revision"] = uint16_bytes_to_string( +        iface->read_eeprom( +            B100_EEPROM_ADDR, +            offsetof(b100_eeprom_map, revision), +            2 +        ) +    ); + +    //extract the product code +    mb_eeprom["product"] = uint16_bytes_to_string( +        iface->read_eeprom( +            B100_EEPROM_ADDR, +            offsetof(b100_eeprom_map, product), +            2 +        ) +    ); + +    //extract the serial +    mb_eeprom["serial"] = bytes_to_string(iface->read_eeprom( +        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, serial), SERIAL_LEN +    )); + +    //extract the name +    mb_eeprom["name"] = bytes_to_string(iface->read_eeprom( +        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, name), NAME_MAX_LEN +    )); + +    return mb_eeprom; +} + +void b100_impl::set_mb_eeprom( +    const uhd::usrp::mboard_eeprom_t &mb_eeprom +) { +    auto &iface = _fx2_ctrl; + +    //parse the revision number +    if (mb_eeprom.has_key("revision")) iface->write_eeprom( +        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, revision), +        string_to_uint16_bytes(mb_eeprom["revision"]) +    ); + +    //parse the product code +    if (mb_eeprom.has_key("product")) iface->write_eeprom( +        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, product), +        string_to_uint16_bytes(mb_eeprom["product"]) +    ); + +    //store the serial +    if (mb_eeprom.has_key("serial")) iface->write_eeprom( +        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, serial), +        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) +    ); + +    //store the name +    if (mb_eeprom.has_key("name")) iface->write_eeprom( +        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, name), +        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) +    ); +} + diff --git a/host/lib/usrp/b200/CMakeLists.txt b/host/lib/usrp/b200/CMakeLists.txt index 4b9e2de55..f5c6e28b2 100644 --- a/host/lib/usrp/b200/CMakeLists.txt +++ b/host/lib/usrp/b200/CMakeLists.txt @@ -30,5 +30,6 @@ IF(ENABLE_B200)          ${CMAKE_CURRENT_SOURCE_DIR}/b200_io_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/b200_uart.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/b200_cores.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/b200_mb_eeprom.cpp      )  ENDIF(ENABLE_B200) diff --git a/host/lib/usrp/b200/b200_image_loader.cpp b/host/lib/usrp/b200/b200_image_loader.cpp index af79a59fc..4d0f8d937 100644 --- a/host/lib/usrp/b200/b200_image_loader.cpp +++ b/host/lib/usrp/b200/b200_image_loader.cpp @@ -46,8 +46,8 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t&      if(dev_handles.size() > 0){          for(usb_device_handle::sptr dev_handle:  dev_handles){              if(dev_handle->firmware_loaded()){ -                iface = b200_iface::make(usb_control::make(dev_handle,0)); -                eeprom = mboard_eeprom_t(*iface, "B200"); +                iface = b200_iface::make(usb_control::make(dev_handle, 0)); +                eeprom = b200_impl::get_mb_eeprom(iface);                  if(user_specified){                      if(image_loader_args.args.has_key("serial") and                         eeprom.get("serial") != image_loader_args.args.get("serial")){ @@ -73,8 +73,10 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t&              std::string err_msg = "Could not resolve given args to a single B2XX device.\n"                                    "Applicable devices:\n"; -            for(usb_device_handle::sptr dev_handle:  applicable_dev_handles){ -                eeprom = mboard_eeprom_t(*b200_iface::make(usb_control::make(dev_handle,0)), "B200"); +            for (usb_device_handle::sptr dev_handle: applicable_dev_handles) { +                eeprom = b200_impl::get_mb_eeprom( +                    b200_iface::make(usb_control::make(dev_handle, 0)) +                );                  err_msg += str(boost::format(" * %s (serial=%s)\n")                                 % B2XX_STR_NAMES.get(get_b200_product(dev_handle, mb_eeprom), "B2XX")                                 % mb_eeprom.get("serial")); @@ -88,7 +90,7 @@ static b200_iface::sptr get_b200_iface(const image_loader::image_loader_args_t&      // No applicable devices found, return empty sptr so we can exit      iface.reset(); -    mb_eeprom = mboard_eeprom_t(); +    mb_eeprom = eeprom;      return iface;  } diff --git a/host/lib/usrp/b200/b200_impl.cpp b/host/lib/usrp/b200/b200_impl.cpp index a513e1336..134cba208 100644 --- a/host/lib/usrp/b200/b200_impl.cpp +++ b/host/lib/usrp/b200/b200_impl.cpp @@ -220,7 +220,7 @@ static device_addrs_t b200_find(const device_addr_t &hint)              catch(const uhd::exception &){continue;} //ignore claimed              b200_iface::sptr iface = b200_iface::make(control); -            const mboard_eeprom_t mb_eeprom = mboard_eeprom_t(*iface, "B200"); +            const mboard_eeprom_t mb_eeprom = b200_impl::get_mb_eeprom(iface);              device_addr_t new_addr;              new_addr["type"] = "b200"; @@ -362,7 +362,7 @@ b200_impl::b200_impl(const uhd::device_addr_t& device_addr, usb_device_handle::s      ////////////////////////////////////////////////////////////////////      // setup the mboard eeprom      //////////////////////////////////////////////////////////////////// -    const mboard_eeprom_t mb_eeprom(*_iface, "B200"); +    const mboard_eeprom_t mb_eeprom = get_mb_eeprom(_iface);      _tree->create<mboard_eeprom_t>(mb_path / "eeprom")          .set(mb_eeprom)          .add_coerced_subscriber(boost::bind(&b200_impl::set_mb_eeprom, this, _1)); @@ -983,11 +983,6 @@ void b200_impl::check_fpga_compat(void)                  % compat_major % compat_minor));  } -void b200_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom) -{ -    mb_eeprom.commit(*_iface, "B200"); -} -  /***********************************************************************   * Reference time and clock   **********************************************************************/ diff --git a/host/lib/usrp/b200/b200_impl.hpp b/host/lib/usrp/b200/b200_impl.hpp index 1c756c56d..a8288df0f 100644 --- a/host/lib/usrp/b200/b200_impl.hpp +++ b/host/lib/usrp/b200/b200_impl.hpp @@ -124,6 +124,8 @@ public:      // uhd::value_error.      void check_streamer_args(const uhd::stream_args_t &args, double tick_rate, const std::string &direction = ""); +    static uhd::usrp::mboard_eeprom_t get_mb_eeprom(uhd::i2c_iface::sptr); +  private:      b200_product_t  _product;      size_t          _revision; diff --git a/host/lib/usrp/b200/b200_mb_eeprom.cpp b/host/lib/usrp/b200/b200_mb_eeprom.cpp new file mode 100644 index 000000000..e56e6f2ec --- /dev/null +++ b/host/lib/usrp/b200/b200_mb_eeprom.cpp @@ -0,0 +1,82 @@ +// +// Copyright 2017 Ettus Research (National Instruments Corp.) +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "b200_impl.hpp" +#include "eeprom_utils.hpp" +#include <uhd/usrp/mboard_eeprom.hpp> + +namespace { +    /* On the B200, this field indicates the slave address. From the FX3, this +     * address is always 0. */ +    static const uint8_t B200_EEPROM_SLAVE_ADDR = 0x04; + +    //use char array so we dont need to attribute packed +    struct b200_eeprom_map{ +        unsigned char _r[220]; +        unsigned char revision[2]; +        unsigned char product[2]; +        unsigned char name[NAME_MAX_LEN]; +        unsigned char serial[SERIAL_LEN]; +    }; +} + +using namespace uhd; +using uhd::usrp::mboard_eeprom_t; + +mboard_eeprom_t b200_impl::get_mb_eeprom(uhd::i2c_iface::sptr iface) +{ +    mboard_eeprom_t mb_eeprom; + +    //extract the revision number +    mb_eeprom["revision"] = uint16_bytes_to_string( +        iface->read_eeprom(B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, revision), 2) +    ); + +    //extract the product code +    mb_eeprom["product"] = uint16_bytes_to_string( +        iface->read_eeprom(B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, product), 2) +    ); + +    //extract the serial +    mb_eeprom["serial"] = bytes_to_string(iface->read_eeprom( +        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, serial), SERIAL_LEN +    )); + +    //extract the name +    mb_eeprom["name"] = bytes_to_string(iface->read_eeprom( +        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, name), NAME_MAX_LEN +    )); + +    return mb_eeprom; +} + +void b200_impl::set_mb_eeprom(const mboard_eeprom_t &mb_eeprom) +{ +    //parse the revision number +    if (mb_eeprom.has_key("revision")) _iface->write_eeprom( +        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, revision), +        string_to_uint16_bytes(mb_eeprom["revision"]) +    ); + +    //parse the product code +    if (mb_eeprom.has_key("product")) _iface->write_eeprom( +        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, product), +        string_to_uint16_bytes(mb_eeprom["product"]) +    ); + +    //store the serial +    if (mb_eeprom.has_key("serial")) _iface->write_eeprom( +        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, serial), +        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) +    ); + +    //store the name +    if (mb_eeprom.has_key("name")) _iface->write_eeprom( +        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, name), +        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) +    ); +} + diff --git a/host/lib/usrp/e100/CMakeLists.txt b/host/lib/usrp/e100/CMakeLists.txt index da77b85dc..5bf7206d0 100644 --- a/host/lib/usrp/e100/CMakeLists.txt +++ b/host/lib/usrp/e100/CMakeLists.txt @@ -34,5 +34,6 @@ IF(ENABLE_E100)          ${CMAKE_CURRENT_SOURCE_DIR}/e100_mmap_zero_copy.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/fpga_downloader.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/mb_eeprom.cpp      )  ENDIF(ENABLE_E100) diff --git a/host/lib/usrp/e100/e100_impl.cpp b/host/lib/usrp/e100/e100_impl.cpp index ddb21fc35..7ee9dccbd 100644 --- a/host/lib/usrp/e100/e100_impl.cpp +++ b/host/lib/usrp/e100/e100_impl.cpp @@ -70,7 +70,8 @@ device_addrs_t e100_find(const device_addr_t &hint){          new_addr["node"] = fs::system_complete(fs::path(hint["node"])).string();          try{              i2c_iface::sptr i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE); -            const mboard_eeprom_t mb_eeprom(*i2c_iface, E100_EEPROM_MAP_KEY); +            const mboard_eeprom_t mb_eeprom = get_mb_eeprom(i2c_iface); +              new_addr["name"] = mb_eeprom["name"];              new_addr["serial"] = mb_eeprom["serial"];          } @@ -108,7 +109,7 @@ static const uhd::dict<std::string, std::string> model_to_fpga_file_name = boost  std::string get_default_e1x0_fpga_image(const uhd::device_addr_t &device_addr){      //read the eeprom so we can determine the hardware      uhd::i2c_iface::sptr dev_i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE); -    const mboard_eeprom_t mb_eeprom(*dev_i2c_iface, E100_EEPROM_MAP_KEY); +    const mboard_eeprom_t mb_eeprom = e100_impl::get_mb_eeprom(dev_i2c_iface);      //determine the model string for this device      const std::string model = device_addr.get("model", mb_eeprom.get("model", "")); @@ -132,8 +133,9 @@ e100_impl::e100_impl(const uhd::device_addr_t &device_addr){      _ignore_cal_file = device_addr.has_key("ignore-cal-file");      _dev_i2c_iface = e100_ctrl::make_dev_i2c_iface(E100_I2C_DEV_NODE); -    const mboard_eeprom_t mb_eeprom(*_dev_i2c_iface, E100_EEPROM_MAP_KEY); -    const std::string default_fpga_file_name = get_default_e1x0_fpga_image(device_addr); +    const mboard_eeprom_t mb_eeprom = get_mb_eeprom(_dev_i2c_iface); +    const std::string default_fpga_file_name = +        get_default_e1x0_fpga_image(device_addr);      const std::string model = device_addr["model"];      std::string e100_fpga_image;      try{ @@ -496,10 +498,6 @@ double e100_impl::update_rx_codec_gain(const double gain){      return _codec_ctrl->get_rx_pga_gain('A');  } -void e100_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){ -    mb_eeprom.commit(*_dev_i2c_iface, E100_EEPROM_MAP_KEY); -} -  void e100_impl::set_db_eeprom(const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){      if (type == "rx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_RX_DB);      if (type == "tx") db_eeprom.store(*_fpga_i2c_ctrl, I2C_ADDR_TX_DB); diff --git a/host/lib/usrp/e100/e100_impl.hpp b/host/lib/usrp/e100/e100_impl.hpp index 5f8277dda..04278d757 100644 --- a/host/lib/usrp/e100/e100_impl.hpp +++ b/host/lib/usrp/e100/e100_impl.hpp @@ -55,7 +55,6 @@ static const uint32_t E100_RX_SID_BASE = 30;  static const uint32_t E100_TX_ASYNC_SID = 10;  static const uint32_t E100_CTRL_MSG_SID = 20;  static const double          E100_DEFAULT_CLOCK_RATE = 64e6; -static const std::string     E100_EEPROM_MAP_KEY = "E100";  //! load an fpga image from a bin file into the usrp-e fpga  extern void e100_load_fpga(const std::string &bin_file); @@ -117,6 +116,7 @@ private:      std::vector<boost::weak_ptr<uhd::tx_streamer> > _tx_streamers;      double update_rx_codec_gain(const double); //sets A and B at once +    uhd::usrp::mboard_eeprom_t get_mb_eeprom();      void set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &);      void set_db_eeprom(const std::string &, const uhd::usrp::dboard_eeprom_t &);      void update_tick_rate(const double rate); diff --git a/host/lib/usrp/e100/mb_eeprom.cpp b/host/lib/usrp/e100/mb_eeprom.cpp new file mode 100644 index 000000000..926688d41 --- /dev/null +++ b/host/lib/usrp/e100/mb_eeprom.cpp @@ -0,0 +1,103 @@ +// +// Copyright 2017 Ettus Research (National Instruments Corp.) +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "e100_impl.hpp" +#include "eeprom_utils.hpp" +#include <uhd/usrp/mboard_eeprom.hpp> + +namespace { + +    const uint8_t E100_EEPROM_ADDR = 0x51; + +    struct e100_eeprom_map{ +        uint16_t vendor; +        uint16_t device; +        unsigned char revision; +        unsigned char content; +        unsigned char model[8]; +        unsigned char env_var[16]; +        unsigned char env_setting[64]; +        unsigned char serial[10]; +        unsigned char name[NAME_MAX_LEN]; +    }; + +    template <typename T> static const byte_vector_t to_bytes(const T &item){ +        return byte_vector_t( +            reinterpret_cast<const byte_vector_t::value_type *>(&item), +            reinterpret_cast<const byte_vector_t::value_type *>(&item)+sizeof(item) +        ); +    } +} + +using namespace uhd; +using uhd::usrp::mboard_eeprom_t; + +mboard_eeprom_t get_mb_eeprom(uhd::i2c_iface::sptr i2c) +{ +    auto &iface = i2c; +    uhd::usrp::mboard_eeprom_t mb_eeprom; + +#define sizeof_member(struct_name, member_name) \ +    sizeof(reinterpret_cast<struct_name*>(0)->member_name) + +    const size_t num_bytes = offsetof(e100_eeprom_map, model); +    byte_vector_t map_bytes = iface->read_eeprom(E100_EEPROM_ADDR, 0, num_bytes); +    e100_eeprom_map map; std::memcpy(&map, &map_bytes[0], map_bytes.size()); + +    mb_eeprom["vendor"] = std::to_string(uhd::ntohx(map.vendor)); +    mb_eeprom["device"] = std::to_string(uhd::ntohx(map.device)); +    mb_eeprom["revision"] = std::to_string(unsigned(map.revision)); +    mb_eeprom["content"] = std::to_string(unsigned(map.content)); + +    #define load_e100_string_xx(key) mb_eeprom[#key] = bytes_to_string(iface->read_eeprom( \ +        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, key), sizeof_member(e100_eeprom_map, key) \ +    )); + +    load_e100_string_xx(model); +    load_e100_string_xx(env_var); +    load_e100_string_xx(env_setting); +    load_e100_string_xx(serial); +    load_e100_string_xx(name); + +    return mb_eeprom; +} + + +void e100_impl::set_mb_eeprom(const mboard_eeprom_t &mb_eeprom) +{ +    auto &iface = _dev_i2c_iface; + +    if (mb_eeprom.has_key("vendor")) iface->write_eeprom( +        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, vendor), +        to_bytes(uhd::htonx(boost::lexical_cast<uint16_t>(mb_eeprom["vendor"]))) +    ); + +    if (mb_eeprom.has_key("device")) iface->write_eeprom( +        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, device), +        to_bytes(uhd::htonx(boost::lexical_cast<uint16_t>(mb_eeprom["device"]))) +    ); + +    if (mb_eeprom.has_key("revision")) iface->write_eeprom( +        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, revision), +        byte_vector_t(1, boost::lexical_cast<unsigned>(mb_eeprom["revision"])) +    ); + +    if (mb_eeprom.has_key("content")) iface->write_eeprom( +        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, content), +        byte_vector_t(1, boost::lexical_cast<unsigned>(mb_eeprom["content"])) +    ); + +    #define store_e100_string_xx(key) if (mb_eeprom.has_key(#key)) iface->write_eeprom( \ +        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, key), \ +        string_to_bytes(mb_eeprom[#key], sizeof_member(e100_eeprom_map, key)) \ +    ); + +    store_e100_string_xx(model); +    store_e100_string_xx(env_var); +    store_e100_string_xx(env_setting); +    store_e100_string_xx(serial); +    store_e100_string_xx(name); +} diff --git a/host/lib/usrp/mboard_eeprom.cpp b/host/lib/usrp/mboard_eeprom.cpp deleted file mode 100644 index f7222426d..000000000 --- a/host/lib/usrp/mboard_eeprom.cpp +++ /dev/null @@ -1,682 +0,0 @@ -// -// Copyright 2010-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 -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. -// - -#include <uhd/usrp/mboard_eeprom.hpp> -#include <uhd/types/byte_vector.hpp> -#include <uhd/types/mac_addr.hpp> -#include <uhd/utils/byteswap.hpp> -#include <boost/asio/ip/address_v4.hpp> -#include <boost/assign/list_of.hpp> -#include <boost/lexical_cast.hpp> -#include <algorithm> -#include <iostream> -#include <cstddef> - -using namespace uhd; -using namespace uhd::usrp; - -/*********************************************************************** - * Constants - **********************************************************************/ -static const size_t SERIAL_LEN = 9; -static const size_t NAME_MAX_LEN = 32 - SERIAL_LEN; - -/*********************************************************************** - * Utility functions - **********************************************************************/ - -//! convert a string to a byte vector to write to eeprom -static byte_vector_t string_to_uint16_bytes(const std::string &num_str){ -    const uint16_t num = boost::lexical_cast<uint16_t>(num_str); -    const byte_vector_t lsb_msb = boost::assign::list_of -        (uint8_t(num >> 0))(uint8_t(num >> 8)); -    return lsb_msb; -} - -//! convert a byte vector read from eeprom to a string -static std::string uint16_bytes_to_string(const byte_vector_t &bytes){ -    const uint16_t num = (uint16_t(bytes.at(0)) << 0) | (uint16_t(bytes.at(1)) << 8); -    return (num == 0 or num == 0xffff)? "" : std::to_string(num); -} - -/*********************************************************************** - * Implementation of N100 load/store - **********************************************************************/ -static const uint8_t N100_EEPROM_ADDR = 0x50; - -struct n100_eeprom_map{ -    uint16_t hardware; -    uint8_t mac_addr[6]; -    uint32_t subnet; -    uint32_t ip_addr; -    uint16_t _pad0; -    uint16_t revision; -    uint16_t product; -    unsigned char _pad1; -    unsigned char gpsdo; -    unsigned char serial[SERIAL_LEN]; -    unsigned char name[NAME_MAX_LEN]; -    uint32_t gateway; -}; - -enum n200_gpsdo_type{ -    N200_GPSDO_NONE = 0, -    N200_GPSDO_INTERNAL = 1, -    N200_GPSDO_ONBOARD = 2 -}; - -static void load_n100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    //extract the hardware number -    mb_eeprom["hardware"] = uint16_bytes_to_string( -        iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, hardware), 2) -    ); - -    //extract the revision number -    mb_eeprom["revision"] = uint16_bytes_to_string( -        iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, revision), 2) -    ); - -    //extract the product code -    mb_eeprom["product"] = uint16_bytes_to_string( -        iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, product), 2) -    ); - -    //extract the addresses -    mb_eeprom["mac-addr"] = mac_addr_t::from_bytes(iface.read_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, mac_addr), 6 -    )).to_string(); - -    boost::asio::ip::address_v4::bytes_type ip_addr_bytes; -    byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, ip_addr), 4), ip_addr_bytes); -    mb_eeprom["ip-addr"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); - -    byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, subnet), 4), ip_addr_bytes); -    mb_eeprom["subnet"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); - -    byte_copy(iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gateway), 4), ip_addr_bytes); -    mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); - -    //gpsdo capabilities -    uint8_t gpsdo_byte = iface.read_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gpsdo), 1).at(0); -    switch(n200_gpsdo_type(gpsdo_byte)){ -    case N200_GPSDO_INTERNAL: mb_eeprom["gpsdo"] = "internal"; break; -    case N200_GPSDO_ONBOARD: mb_eeprom["gpsdo"] = "onboard"; break; -    default: mb_eeprom["gpsdo"] = "none"; -    } - -    //extract the serial -    mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, serial), SERIAL_LEN -    )); - -    //extract the name -    mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, name), NAME_MAX_LEN -    )); - -    //Empty serial correction: use the mac address to determine serial. -    //Older usrp2 models don't have a serial burned into EEPROM. -    //The lower mac address bits will function as the serial number. -    if (mb_eeprom["serial"].empty()){ -        byte_vector_t mac_addr_bytes = mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes(); -        unsigned serial = mac_addr_bytes.at(5) | (unsigned(mac_addr_bytes.at(4) & 0x0f) << 8); -        mb_eeprom["serial"] = std::to_string(serial); -    } -} - -static void store_n100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    //parse the revision number -    if (mb_eeprom.has_key("hardware")) iface.write_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, hardware), -        string_to_uint16_bytes(mb_eeprom["hardware"]) -    ); - -    //parse the revision number -    if (mb_eeprom.has_key("revision")) iface.write_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, revision), -        string_to_uint16_bytes(mb_eeprom["revision"]) -    ); - -    //parse the product code -    if (mb_eeprom.has_key("product")) iface.write_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, product), -        string_to_uint16_bytes(mb_eeprom["product"]) -    ); - -    //store the addresses -    if (mb_eeprom.has_key("mac-addr")) iface.write_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, mac_addr), -        mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes() -    ); - -    if (mb_eeprom.has_key("ip-addr")){ -        byte_vector_t ip_addr_bytes(4); -        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"]).to_bytes(), ip_addr_bytes); -        iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, ip_addr), ip_addr_bytes); -    } - -    if (mb_eeprom.has_key("subnet")){ -        byte_vector_t ip_addr_bytes(4); -        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"]).to_bytes(), ip_addr_bytes); -        iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, subnet), ip_addr_bytes); -    } - -    if (mb_eeprom.has_key("gateway")){ -        byte_vector_t ip_addr_bytes(4); -        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(), ip_addr_bytes); -        iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gateway), ip_addr_bytes); -    } - -    //gpsdo capabilities -    if (mb_eeprom.has_key("gpsdo")){ -        uint8_t gpsdo_byte = N200_GPSDO_NONE; -        if (mb_eeprom["gpsdo"] == "internal") gpsdo_byte = N200_GPSDO_INTERNAL; -        if (mb_eeprom["gpsdo"] == "onboard") gpsdo_byte = N200_GPSDO_ONBOARD; -        iface.write_eeprom(N100_EEPROM_ADDR, offsetof(n100_eeprom_map, gpsdo), byte_vector_t(1, gpsdo_byte)); -    } - -    //store the serial -    if (mb_eeprom.has_key("serial")) iface.write_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, serial), -        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) -    ); - -    //store the name -    if (mb_eeprom.has_key("name")) iface.write_eeprom( -        N100_EEPROM_ADDR, offsetof(n100_eeprom_map, name), -        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) -    ); -} - -/*********************************************************************** - * Implementation of X300 load/store - **********************************************************************/ -static const uint8_t X300_EEPROM_ADDR = 0x50; - -struct x300_eeprom_map -{ -    //indentifying numbers -    unsigned char revision[2]; -    unsigned char product[2]; -    unsigned char revision_compat[2]; -    uint8_t _pad0[2]; - -    //all the mac addrs -    uint8_t mac_addr0[6]; -    uint8_t _pad1[2]; -    uint8_t mac_addr1[6]; -    uint8_t _pad2[2]; - -    //all the IP addrs -    uint32_t gateway; -    uint32_t subnet[4]; -    uint32_t ip_addr[4]; -    uint8_t _pad3[16]; - -    //names and serials -    unsigned char name[NAME_MAX_LEN]; -    unsigned char serial[SERIAL_LEN]; -}; - -static void load_x300(mboard_eeprom_t &mb_eeprom, i2c_iface &iface) -{ -    byte_vector_t bytes = iface.read_eeprom(X300_EEPROM_ADDR, 0, sizeof (struct x300_eeprom_map)); - -    if (bytes.size() == 0) -    { -        return; -    } - -    //extract the revision number -    mb_eeprom["revision"] = uint16_bytes_to_string( -            byte_vector_t( -            bytes.begin() + offsetof(x300_eeprom_map, revision), -            bytes.begin() + (offsetof(x300_eeprom_map, revision)+2)) -    ); - -    //extract the revision compat number -    mb_eeprom["revision_compat"] = uint16_bytes_to_string( -            byte_vector_t( -            bytes.begin() + offsetof(x300_eeprom_map, revision_compat), -            bytes.begin() + (offsetof(x300_eeprom_map, revision_compat)+2)) -    ); - -    //extract the product code -    mb_eeprom["product"] = uint16_bytes_to_string( -            byte_vector_t( -            bytes.begin() + offsetof(x300_eeprom_map, product), -            bytes.begin() + (offsetof(x300_eeprom_map, product)+2)) -    ); - -    //extract the mac addresses -    mb_eeprom["mac-addr0"] = mac_addr_t::from_bytes( -            byte_vector_t( -            bytes.begin() + offsetof(x300_eeprom_map, mac_addr0), -            bytes.begin() + (offsetof(x300_eeprom_map, mac_addr0)+6)) -    ).to_string(); -    mb_eeprom["mac-addr1"] = mac_addr_t::from_bytes( -            byte_vector_t( -            bytes.begin() + offsetof(x300_eeprom_map, mac_addr1), -            bytes.begin() + (offsetof(x300_eeprom_map, mac_addr1)+6)) -    ).to_string(); - -    //extract the ip addresses -    boost::asio::ip::address_v4::bytes_type ip_addr_bytes; -    byte_copy( -            byte_vector_t( -            bytes.begin() + offsetof(x300_eeprom_map, gateway), -            bytes.begin() + (offsetof(x300_eeprom_map, gateway)+4)), -            ip_addr_bytes -    ); -    mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); -    for (size_t i = 0; i < 4; i++) -    { -        const std::string n(1, i+'0'); -        byte_copy( -                byte_vector_t( -                bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)), -                bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)+4)), -                ip_addr_bytes -        ); -        mb_eeprom["ip-addr"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); - -        byte_copy( -                byte_vector_t( -                bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)), -                bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)+4)), -                ip_addr_bytes -        ); -        mb_eeprom["subnet"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); -    } - -    //extract the serial -    mb_eeprom["serial"] = bytes_to_string( -            byte_vector_t( -            bytes.begin() + offsetof(x300_eeprom_map, serial), -            bytes.begin() + (offsetof(x300_eeprom_map, serial)+SERIAL_LEN)) -    ); - -    //extract the name -    mb_eeprom["name"] = bytes_to_string( -            byte_vector_t( -            bytes.begin() + offsetof(x300_eeprom_map, name), -            bytes.begin() + (offsetof(x300_eeprom_map, name)+NAME_MAX_LEN)) -    ); -} - -static void store_x300(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface) -{ -    //parse the revision number -    if (mb_eeprom.has_key("revision")) iface.write_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision), -        string_to_uint16_bytes(mb_eeprom["revision"]) -    ); - -    //parse the revision compat number -    if (mb_eeprom.has_key("revision_compat")) iface.write_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision_compat), -        string_to_uint16_bytes(mb_eeprom["revision_compat"]) -    ); - -    //parse the product code -    if (mb_eeprom.has_key("product")) iface.write_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, product), -        string_to_uint16_bytes(mb_eeprom["product"]) -    ); - -    //store the mac addresses -    if (mb_eeprom.has_key("mac-addr0")) iface.write_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr0), -        mac_addr_t::from_string(mb_eeprom["mac-addr0"]).to_bytes() -    ); -    if (mb_eeprom.has_key("mac-addr1")) iface.write_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr1), -        mac_addr_t::from_string(mb_eeprom["mac-addr1"]).to_bytes() -    ); - -    //store the ip addresses -    byte_vector_t ip_addr_bytes(4); -    if (mb_eeprom.has_key("gateway")){ -        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(), ip_addr_bytes); -        iface.write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, gateway), ip_addr_bytes); -    } -    for (size_t i = 0; i < 4; i++) -    { -        const std::string n(1, i+'0'); -        if (mb_eeprom.has_key("ip-addr"+n)){ -            byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"+n]).to_bytes(), ip_addr_bytes); -            iface.write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, ip_addr)+(i*4), ip_addr_bytes); -        } - -        if (mb_eeprom.has_key("subnet"+n)){ -            byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"+n]).to_bytes(), ip_addr_bytes); -            iface.write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, subnet)+(i*4), ip_addr_bytes); -        } -    } - -    //store the serial -    if (mb_eeprom.has_key("serial")) iface.write_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, serial), -        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) -    ); - -    //store the name -    if (mb_eeprom.has_key("name")) iface.write_eeprom( -        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, name), -        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) -    ); -} - -/*********************************************************************** - * Implementation of B000 load/store - **********************************************************************/ -static const uint8_t B000_EEPROM_ADDR = 0x50; -static const size_t B000_SERIAL_LEN = 8; - -//use char array so we dont need to attribute packed -struct b000_eeprom_map{ -    unsigned char _r[221]; -    unsigned char mcr[4]; -    unsigned char name[NAME_MAX_LEN]; -    unsigned char serial[B000_SERIAL_LEN]; -}; - -static void load_b000(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    //extract the serial -    mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( -        B000_EEPROM_ADDR, offsetof(b000_eeprom_map, serial), B000_SERIAL_LEN -    )); - -    //extract the name -    mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( -        B000_EEPROM_ADDR, offsetof(b000_eeprom_map, name), NAME_MAX_LEN -    )); - -    //extract master clock rate as a 32-bit uint in Hz -    uint32_t master_clock_rate; -    const byte_vector_t rate_bytes = iface.read_eeprom( -        B000_EEPROM_ADDR, offsetof(b000_eeprom_map, mcr), sizeof(master_clock_rate) -    ); -    std::copy( -        rate_bytes.begin(), rate_bytes.end(), //input -        reinterpret_cast<uint8_t *>(&master_clock_rate) //output -    ); -    master_clock_rate = ntohl(master_clock_rate); -    if (master_clock_rate > 1e6 and master_clock_rate < 1e9){ -        mb_eeprom["mcr"] = std::to_string(master_clock_rate); -    } -    else mb_eeprom["mcr"] = ""; -} - -static void store_b000(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    //store the serial -    if (mb_eeprom.has_key("serial")) iface.write_eeprom( -        B000_EEPROM_ADDR, offsetof(b000_eeprom_map, serial), -        string_to_bytes(mb_eeprom["serial"], B000_SERIAL_LEN) -    ); - -    //store the name -    if (mb_eeprom.has_key("name")) iface.write_eeprom( -        B000_EEPROM_ADDR, offsetof(b000_eeprom_map, name), -        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) -    ); - -    //store the master clock rate as a 32-bit uint in Hz -    if (mb_eeprom.has_key("mcr")){ -        uint32_t master_clock_rate = uint32_t(std::stod(mb_eeprom["mcr"])); -        master_clock_rate = htonl(master_clock_rate); -        const byte_vector_t rate_bytes( -            reinterpret_cast<const uint8_t *>(&master_clock_rate), -            reinterpret_cast<const uint8_t *>(&master_clock_rate) + sizeof(master_clock_rate) -        ); -        iface.write_eeprom( -            B000_EEPROM_ADDR, offsetof(b000_eeprom_map, mcr), rate_bytes -        ); -    } -} - -/*********************************************************************** - * Implementation of B100 load/store - **********************************************************************/ -static const uint8_t B100_EEPROM_ADDR = 0x50; - -//use char array so we dont need to attribute packed -struct b100_eeprom_map{ -    unsigned char _r[220]; -    unsigned char revision[2]; -    unsigned char product[2]; -    unsigned char name[NAME_MAX_LEN]; -    unsigned char serial[SERIAL_LEN]; -}; - -static void load_b100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    //extract the revision number -    mb_eeprom["revision"] = uint16_bytes_to_string( -        iface.read_eeprom(B100_EEPROM_ADDR, offsetof(b100_eeprom_map, revision), 2) -    ); - -    //extract the product code -    mb_eeprom["product"] = uint16_bytes_to_string( -        iface.read_eeprom(B100_EEPROM_ADDR, offsetof(b100_eeprom_map, product), 2) -    ); - -    //extract the serial -    mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( -        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, serial), SERIAL_LEN -    )); - -    //extract the name -    mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( -        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, name), NAME_MAX_LEN -    )); -} - -static void store_b100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    //parse the revision number -    if (mb_eeprom.has_key("revision")) iface.write_eeprom( -        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, revision), -        string_to_uint16_bytes(mb_eeprom["revision"]) -    ); - -    //parse the product code -    if (mb_eeprom.has_key("product")) iface.write_eeprom( -        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, product), -        string_to_uint16_bytes(mb_eeprom["product"]) -    ); - -    //store the serial -    if (mb_eeprom.has_key("serial")) iface.write_eeprom( -        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, serial), -        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) -    ); - -    //store the name -    if (mb_eeprom.has_key("name")) iface.write_eeprom( -        B100_EEPROM_ADDR, offsetof(b100_eeprom_map, name), -        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) -    ); -} - -/*********************************************************************** - * Implementation of B200 load/store - **********************************************************************/ -/* On the B200, this field indicates the slave address. From the FX3, this - * address is always 0. */ -static const uint8_t B200_EEPROM_SLAVE_ADDR = 0x04; - -//use char array so we dont need to attribute packed -struct b200_eeprom_map{ -    unsigned char _r[220]; -    unsigned char revision[2]; -    unsigned char product[2]; -    unsigned char name[NAME_MAX_LEN]; -    unsigned char serial[SERIAL_LEN]; -}; - -static void load_b200(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    //extract the revision number -    mb_eeprom["revision"] = uint16_bytes_to_string( -        iface.read_eeprom(B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, revision), 2) -    ); - -    //extract the product code -    mb_eeprom["product"] = uint16_bytes_to_string( -        iface.read_eeprom(B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, product), 2) -    ); - -    //extract the serial -    mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( -        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, serial), SERIAL_LEN -    )); - -    //extract the name -    mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( -        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, name), NAME_MAX_LEN -    )); -} - -static void store_b200(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    //parse the revision number -    if (mb_eeprom.has_key("revision")) iface.write_eeprom( -        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, revision), -        string_to_uint16_bytes(mb_eeprom["revision"]) -    ); - -    //parse the product code -    if (mb_eeprom.has_key("product")) iface.write_eeprom( -        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, product), -        string_to_uint16_bytes(mb_eeprom["product"]) -    ); - -    //store the serial -    if (mb_eeprom.has_key("serial")) iface.write_eeprom( -        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, serial), -        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) -    ); - -    //store the name -    if (mb_eeprom.has_key("name")) iface.write_eeprom( -        B200_EEPROM_SLAVE_ADDR, offsetof(b200_eeprom_map, name), -        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) -    ); -} -/*********************************************************************** - * Implementation of E100 load/store - **********************************************************************/ -static const uint8_t E100_EEPROM_ADDR = 0x51; - -struct e100_eeprom_map{ -    uint16_t vendor; -    uint16_t device; -    unsigned char revision; -    unsigned char content; -    unsigned char model[8]; -    unsigned char env_var[16]; -    unsigned char env_setting[64]; -    unsigned char serial[10]; -    unsigned char name[NAME_MAX_LEN]; -}; - -template <typename T> static const byte_vector_t to_bytes(const T &item){ -    return byte_vector_t( -        reinterpret_cast<const byte_vector_t::value_type *>(&item), -        reinterpret_cast<const byte_vector_t::value_type *>(&item)+sizeof(item) -    ); -} - -#define sizeof_member(struct_name, member_name) \ -    sizeof(reinterpret_cast<struct_name*>(0)->member_name) - -static void load_e100(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ -    const size_t num_bytes = offsetof(e100_eeprom_map, model); -    byte_vector_t map_bytes = iface.read_eeprom(E100_EEPROM_ADDR, 0, num_bytes); -    e100_eeprom_map map; std::memcpy(&map, &map_bytes[0], map_bytes.size()); - -    mb_eeprom["vendor"] = std::to_string(uhd::ntohx(map.vendor)); -    mb_eeprom["device"] = std::to_string(uhd::ntohx(map.device)); -    mb_eeprom["revision"] = std::to_string(unsigned(map.revision)); -    mb_eeprom["content"] = std::to_string(unsigned(map.content)); - -    #define load_e100_string_xx(key) mb_eeprom[#key] = bytes_to_string(iface.read_eeprom( \ -        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, key), sizeof_member(e100_eeprom_map, key) \ -    )); - -    load_e100_string_xx(model); -    load_e100_string_xx(env_var); -    load_e100_string_xx(env_setting); -    load_e100_string_xx(serial); -    load_e100_string_xx(name); -} - -static void store_e100(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){ - -    if (mb_eeprom.has_key("vendor")) iface.write_eeprom( -        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, vendor), -        to_bytes(uhd::htonx(boost::lexical_cast<uint16_t>(mb_eeprom["vendor"]))) -    ); - -    if (mb_eeprom.has_key("device")) iface.write_eeprom( -        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, device), -        to_bytes(uhd::htonx(boost::lexical_cast<uint16_t>(mb_eeprom["device"]))) -    ); - -    if (mb_eeprom.has_key("revision")) iface.write_eeprom( -        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, revision), -        byte_vector_t(1, boost::lexical_cast<unsigned>(mb_eeprom["revision"])) -    ); - -    if (mb_eeprom.has_key("content")) iface.write_eeprom( -        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, content), -        byte_vector_t(1, boost::lexical_cast<unsigned>(mb_eeprom["content"])) -    ); - -    #define store_e100_string_xx(key) if (mb_eeprom.has_key(#key)) iface.write_eeprom( \ -        E100_EEPROM_ADDR, offsetof(e100_eeprom_map, key), \ -        string_to_bytes(mb_eeprom[#key], sizeof_member(e100_eeprom_map, key)) \ -    ); - -    store_e100_string_xx(model); -    store_e100_string_xx(env_var); -    store_e100_string_xx(env_setting); -    store_e100_string_xx(serial); -    store_e100_string_xx(name); -} - -/*********************************************************************** - * Implementation of mboard eeprom - **********************************************************************/ -mboard_eeprom_t::mboard_eeprom_t(void){ -    /* NOP */ -} - -mboard_eeprom_t::mboard_eeprom_t(i2c_iface &iface, const std::string &which){ -    if (which == "N100") load_n100(*this, iface); -    if (which == "X300") load_x300(*this, iface); -    if (which == "B000") load_b000(*this, iface); -    if (which == "B100") load_b100(*this, iface); -    if (which == "B200") load_b200(*this, iface); -    if (which == "E100") load_e100(*this, iface); -} - -void mboard_eeprom_t::commit(i2c_iface &iface, const std::string &which) const{ -    if (which == "N100") store_n100(*this, iface); -    if (which == "X300") store_x300(*this, iface); -    if (which == "B000") store_b000(*this, iface); -    if (which == "B100") store_b100(*this, iface); -    if (which == "B200") store_b200(*this, iface); -    if (which == "E100") store_e100(*this, iface); -} diff --git a/host/lib/usrp/usrp1/CMakeLists.txt b/host/lib/usrp/usrp1/CMakeLists.txt index 6924ba3b0..e212e924a 100644 --- a/host/lib/usrp/usrp1/CMakeLists.txt +++ b/host/lib/usrp/usrp1/CMakeLists.txt @@ -27,6 +27,7 @@ IF(ENABLE_USRP1)          ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/mb_eeprom.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/soft_time_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp1_impl.cpp diff --git a/host/lib/usrp/usrp1/mb_eeprom.cpp b/host/lib/usrp/usrp1/mb_eeprom.cpp new file mode 100644 index 000000000..ba05b6fd0 --- /dev/null +++ b/host/lib/usrp/usrp1/mb_eeprom.cpp @@ -0,0 +1,90 @@ +// +// Copyright 2017 Ettus Research (National Instruments Corp.) +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "usrp1_impl.hpp" +#include "eeprom_utils.hpp" +#include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/byte_vector.hpp> + +namespace { +    const uint8_t USRP1_EEPROM_ADDR = 0x50; +    const size_t USRP1_SERIAL_LEN = 8; + +    //use char array so we dont need to attribute packed +    struct usrp1_eeprom_map{ +        unsigned char _r[221]; +        unsigned char mcr[4]; +        unsigned char name[NAME_MAX_LEN]; +        unsigned char serial[USRP1_SERIAL_LEN]; +    }; +} + +using namespace uhd; +using uhd::usrp::mboard_eeprom_t; + +mboard_eeprom_t usrp1_impl::get_mb_eeprom(uhd::i2c_iface::sptr iface) +{ +    mboard_eeprom_t mb_eeprom; + +    //extract the serial +    mb_eeprom["serial"] = uhd::bytes_to_string(iface->read_eeprom( +        USRP1_EEPROM_ADDR, offsetof(usrp1_eeprom_map, serial), USRP1_SERIAL_LEN +    )); + +    //extract the name +    mb_eeprom["name"] = uhd::bytes_to_string(iface->read_eeprom( +        USRP1_EEPROM_ADDR, offsetof(usrp1_eeprom_map, name), NAME_MAX_LEN +    )); + +    //extract master clock rate as a 32-bit uint in Hz +    uint32_t master_clock_rate; +    const byte_vector_t rate_bytes = iface->read_eeprom( +        USRP1_EEPROM_ADDR, offsetof(usrp1_eeprom_map, mcr), sizeof(master_clock_rate) +    ); +    std::copy( +        rate_bytes.begin(), rate_bytes.end(), //input +        reinterpret_cast<uint8_t *>(&master_clock_rate) //output +    ); +    master_clock_rate = ntohl(master_clock_rate); +    if (master_clock_rate > 1e6 and master_clock_rate < 1e9){ +        mb_eeprom["mcr"] = std::to_string(master_clock_rate); +    } +    else mb_eeprom["mcr"] = ""; + +    return mb_eeprom; +} + +void usrp1_impl::set_mb_eeprom(const mboard_eeprom_t &mb_eeprom) +{ +    auto &iface = _fx2_ctrl; + +    //store the serial +    if (mb_eeprom.has_key("serial")) iface->write_eeprom( +        USRP1_EEPROM_ADDR, offsetof(usrp1_eeprom_map, serial), +        string_to_bytes(mb_eeprom["serial"], USRP1_SERIAL_LEN) +    ); + +    //store the name +    if (mb_eeprom.has_key("name")) iface->write_eeprom( +        USRP1_EEPROM_ADDR, offsetof(usrp1_eeprom_map, name), +        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) +    ); + +    //store the master clock rate as a 32-bit uint in Hz +    if (mb_eeprom.has_key("mcr")){ +        uint32_t master_clock_rate = uint32_t(std::stod(mb_eeprom["mcr"])); +        master_clock_rate = htonl(master_clock_rate); +        const byte_vector_t rate_bytes( +            reinterpret_cast<const uint8_t *>(&master_clock_rate), +            reinterpret_cast<const uint8_t *>(&master_clock_rate) +                + sizeof(master_clock_rate) +        ); +        iface->write_eeprom( +            USRP1_EEPROM_ADDR, offsetof(usrp1_eeprom_map, mcr), rate_bytes +        ); +    } +} + diff --git a/host/lib/usrp/usrp1/usrp1_impl.cpp b/host/lib/usrp/usrp1/usrp1_impl.cpp index 92b7f5331..17009c6a9 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.cpp +++ b/host/lib/usrp/usrp1/usrp1_impl.cpp @@ -111,7 +111,8 @@ static device_addrs_t usrp1_find(const device_addr_t &hint)              catch(const uhd::exception &){continue;} //ignore claimed              fx2_ctrl::sptr fx2_ctrl = fx2_ctrl::make(control); -            const mboard_eeprom_t mb_eeprom(*fx2_ctrl, USRP1_EEPROM_MAP_KEY); +            const mboard_eeprom_t mb_eeprom = +                usrp1_impl::get_mb_eeprom(fx2_ctrl);              device_addr_t new_addr;              new_addr["type"] = "usrp1";              new_addr["name"] = mb_eeprom["name"]; @@ -218,7 +219,8 @@ usrp1_impl::usrp1_impl(const device_addr_t &device_addr){      ////////////////////////////////////////////////////////////////////      // setup the mboard eeprom      //////////////////////////////////////////////////////////////////// -    const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, USRP1_EEPROM_MAP_KEY); +    //const mboard_eeprom_t mb_eeprom(*_fx2_ctrl, USRP1_EEPROM_MAP_KEY); +    const mboard_eeprom_t mb_eeprom = this->get_mb_eeprom(_fx2_ctrl);      _tree->create<mboard_eeprom_t>(mb_path / "eeprom")          .set(mb_eeprom)          .add_coerced_subscriber(boost::bind(&usrp1_impl::set_mb_eeprom, this, _1)); @@ -452,10 +454,6 @@ bool usrp1_impl::has_tx_halfband(void){  /***********************************************************************   * Properties callback methods below   **********************************************************************/ -void usrp1_impl::set_mb_eeprom(const uhd::usrp::mboard_eeprom_t &mb_eeprom){ -    mb_eeprom.commit(*_fx2_ctrl, USRP1_EEPROM_MAP_KEY); -} -  void usrp1_impl::set_db_eeprom(const std::string &db, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){      if (type == "rx") db_eeprom.store(*_fx2_ctrl, (db == "A")? (I2C_ADDR_RX_A) : (I2C_ADDR_RX_B));      if (type == "tx") db_eeprom.store(*_fx2_ctrl, (db == "A")? (I2C_ADDR_TX_A) : (I2C_ADDR_TX_B)); diff --git a/host/lib/usrp/usrp1/usrp1_impl.hpp b/host/lib/usrp/usrp1/usrp1_impl.hpp index b45d138d1..ca192f907 100644 --- a/host/lib/usrp/usrp1/usrp1_impl.hpp +++ b/host/lib/usrp/usrp1/usrp1_impl.hpp @@ -84,6 +84,8 @@ public:      uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args);      bool recv_async_msg(uhd::async_metadata_t &, double); +    static uhd::usrp::mboard_eeprom_t get_mb_eeprom(uhd::i2c_iface::sptr); +  private:      //controllers      uhd::usrp::fx2_ctrl::sptr _fx2_ctrl; diff --git a/host/lib/usrp/usrp2/CMakeLists.txt b/host/lib/usrp/usrp2/CMakeLists.txt index edf77a654..a5aaf3eeb 100644 --- a/host/lib/usrp/usrp2/CMakeLists.txt +++ b/host/lib/usrp/usrp2/CMakeLists.txt @@ -28,6 +28,7 @@ IF(ENABLE_USRP2)          ${CMAKE_CURRENT_SOURCE_DIR}/codec_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/dboard_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/io_impl.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/mb_eeprom.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_impl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/usrp2_fifo_ctrl.cpp diff --git a/host/lib/usrp/usrp2/mb_eeprom.cpp b/host/lib/usrp/usrp2/mb_eeprom.cpp new file mode 100644 index 000000000..5b86633d6 --- /dev/null +++ b/host/lib/usrp/usrp2/mb_eeprom.cpp @@ -0,0 +1,175 @@ +// +// Copyright 2017 Ettus Research (National Instruments Corp.) +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "usrp2_impl.hpp" +#include "eeprom_utils.hpp" +#include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/byte_vector.hpp> +#include <uhd/types/mac_addr.hpp> +#include <boost/asio/ip/address_v4.hpp> + +namespace { +    const uint8_t N200_EEPROM_ADDR = 0x50; + +    struct n200_eeprom_map{ +        uint16_t hardware; +        uint8_t mac_addr[6]; +        uint32_t subnet; +        uint32_t ip_addr; +        uint16_t _pad0; +        uint16_t revision; +        uint16_t product; +        unsigned char _pad1; +        unsigned char gpsdo; +        unsigned char serial[SERIAL_LEN]; +        unsigned char name[NAME_MAX_LEN]; +        uint32_t gateway; +    }; + +    enum n200_gpsdo_type{ +        N200_GPSDO_NONE = 0, +        N200_GPSDO_INTERNAL = 1, +        N200_GPSDO_ONBOARD = 2 +    }; +} + +using namespace uhd; +using uhd::usrp::mboard_eeprom_t; + +mboard_eeprom_t usrp2_impl::get_mb_eeprom(usrp2_iface &iface) +{ +    uhd::usrp::mboard_eeprom_t mb_eeprom; + +    //extract the hardware number +    mb_eeprom["hardware"] = uint16_bytes_to_string( +        iface.read_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, hardware), 2) +    ); + +    //extract the revision number +    mb_eeprom["revision"] = uint16_bytes_to_string( +        iface.read_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, revision), 2) +    ); + +    //extract the product code +    mb_eeprom["product"] = uint16_bytes_to_string( +        iface.read_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, product), 2) +    ); + +    //extract the addresses +    mb_eeprom["mac-addr"] = mac_addr_t::from_bytes(iface.read_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, mac_addr), 6 +    )).to_string(); + +    boost::asio::ip::address_v4::bytes_type ip_addr_bytes; +    byte_copy(iface.read_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, ip_addr), 4), ip_addr_bytes); +    mb_eeprom["ip-addr"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); + +    byte_copy(iface.read_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, subnet), 4), ip_addr_bytes); +    mb_eeprom["subnet"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); + +    byte_copy(iface.read_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, gateway), 4), ip_addr_bytes); +    mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); + +    //gpsdo capabilities +    uint8_t gpsdo_byte = iface.read_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, gpsdo), 1).at(0); +    switch(n200_gpsdo_type(gpsdo_byte)){ +    case N200_GPSDO_INTERNAL: mb_eeprom["gpsdo"] = "internal"; break; +    case N200_GPSDO_ONBOARD: mb_eeprom["gpsdo"] = "onboard"; break; +    default: mb_eeprom["gpsdo"] = "none"; +    } + +    //extract the serial +    mb_eeprom["serial"] = bytes_to_string(iface.read_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, serial), SERIAL_LEN +    )); + +    //extract the name +    mb_eeprom["name"] = bytes_to_string(iface.read_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, name), NAME_MAX_LEN +    )); + +    //Empty serial correction: use the mac address to determine serial. +    //Older usrp2 models don't have a serial burned into EEPROM. +    //The lower mac address bits will function as the serial number. +    if (mb_eeprom["serial"].empty()){ +        byte_vector_t mac_addr_bytes = mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes(); +        unsigned serial = mac_addr_bytes.at(5) | (unsigned(mac_addr_bytes.at(4) & 0x0f) << 8); +        mb_eeprom["serial"] = std::to_string(serial); +    } + +    return mb_eeprom; +} + + +void usrp2_impl::set_mb_eeprom( +    const std::string &mb, +    const mboard_eeprom_t &mb_eeprom +) { +    auto &iface = _mbc[mb].iface; + +    //parse the revision number +    if (mb_eeprom.has_key("hardware")) iface->write_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, hardware), +        string_to_uint16_bytes(mb_eeprom["hardware"]) +    ); + +    //parse the revision number +    if (mb_eeprom.has_key("revision")) iface->write_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, revision), +        string_to_uint16_bytes(mb_eeprom["revision"]) +    ); + +    //parse the product code +    if (mb_eeprom.has_key("product")) iface->write_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, product), +        string_to_uint16_bytes(mb_eeprom["product"]) +    ); + +    //store the addresses +    if (mb_eeprom.has_key("mac-addr")) iface->write_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, mac_addr), +        mac_addr_t::from_string(mb_eeprom["mac-addr"]).to_bytes() +    ); + +    if (mb_eeprom.has_key("ip-addr")){ +        byte_vector_t ip_addr_bytes(4); +        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"]).to_bytes(), ip_addr_bytes); +        iface->write_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, ip_addr), ip_addr_bytes); +    } + +    if (mb_eeprom.has_key("subnet")){ +        byte_vector_t ip_addr_bytes(4); +        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"]).to_bytes(), ip_addr_bytes); +        iface->write_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, subnet), ip_addr_bytes); +    } + +    if (mb_eeprom.has_key("gateway")){ +        byte_vector_t ip_addr_bytes(4); +        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(), ip_addr_bytes); +        iface->write_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, gateway), ip_addr_bytes); +    } + +    //gpsdo capabilities +    if (mb_eeprom.has_key("gpsdo")){ +        uint8_t gpsdo_byte = N200_GPSDO_NONE; +        if (mb_eeprom["gpsdo"] == "internal") gpsdo_byte = N200_GPSDO_INTERNAL; +        if (mb_eeprom["gpsdo"] == "onboard") gpsdo_byte = N200_GPSDO_ONBOARD; +        iface->write_eeprom(N200_EEPROM_ADDR, offsetof(n200_eeprom_map, gpsdo), byte_vector_t(1, gpsdo_byte)); +    } + +    //store the serial +    if (mb_eeprom.has_key("serial")) iface->write_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, serial), +        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) +    ); + +    //store the name +    if (mb_eeprom.has_key("name")) iface->write_eeprom( +        N200_EEPROM_ADDR, offsetof(n200_eeprom_map, name), +        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) +    ); +} + diff --git a/host/lib/usrp/usrp2/usrp2_iface.cpp b/host/lib/usrp/usrp2/usrp2_iface.cpp index ce547bad0..46e4198b0 100644 --- a/host/lib/usrp/usrp2/usrp2_iface.cpp +++ b/host/lib/usrp/usrp2/usrp2_iface.cpp @@ -83,7 +83,7 @@ public:              throw uhd::runtime_error("firmware not responding");          _protocol_compat = ntohl(ctrl_data.proto_ver); -        mb_eeprom = mboard_eeprom_t(*this, USRP2_EEPROM_MAP_KEY); +        mb_eeprom = usrp2_impl::get_mb_eeprom(*this);      }      ~usrp2_iface_impl(void){UHD_SAFE_CALL( diff --git a/host/lib/usrp/usrp2/usrp2_impl.cpp b/host/lib/usrp/usrp2/usrp2_impl.cpp index 573314339..90b949759 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.cpp +++ b/host/lib/usrp/usrp2/usrp2_impl.cpp @@ -473,7 +473,8 @@ usrp2_impl::usrp2_impl(const device_addr_t &_device_addr) :          ////////////////////////////////////////////////////////////////          _tree->create<mboard_eeprom_t>(mb_path / "eeprom")              .set(_mbc[mb].iface->mb_eeprom) -            .add_coerced_subscriber(boost::bind(&usrp2_impl::set_mb_eeprom, this, mb, _1)); +            .add_coerced_subscriber( +                boost::bind(&usrp2_impl::set_mb_eeprom, this, mb, _1));          ////////////////////////////////////////////////////////////////          // create clock control objects @@ -792,10 +793,6 @@ usrp2_impl::~usrp2_impl(void){UHD_SAFE_CALL(      }  )} -void usrp2_impl::set_mb_eeprom(const std::string &mb, const uhd::usrp::mboard_eeprom_t &mb_eeprom){ -    mb_eeprom.commit(*(_mbc[mb].iface), USRP2_EEPROM_MAP_KEY); -} -  void usrp2_impl::set_db_eeprom(const std::string &mb, const std::string &type, const uhd::usrp::dboard_eeprom_t &db_eeprom){      if (type == "rx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_RX_DB);      if (type == "tx") db_eeprom.store(*_mbc[mb].iface, USRP2_I2C_ADDR_TX_DB); diff --git a/host/lib/usrp/usrp2/usrp2_impl.hpp b/host/lib/usrp/usrp2/usrp2_impl.hpp index 087a4f8e9..e3cd5628e 100644 --- a/host/lib/usrp/usrp2/usrp2_impl.hpp +++ b/host/lib/usrp/usrp2/usrp2_impl.hpp @@ -55,7 +55,6 @@ static const size_t mimo_clock_sync_delay_cycles = 138;  static const size_t USRP2_SRAM_BYTES = size_t(1 << 20);  static const uint32_t USRP2_TX_ASYNC_SID = 2;  static const uint32_t USRP2_RX_SID_BASE = 3; -static const std::string USRP2_EEPROM_MAP_KEY = "N100";  uhd::device_addrs_t usrp2_find(const uhd::device_addr_t &hint_); @@ -82,6 +81,8 @@ public:      uhd::tx_streamer::sptr get_tx_stream(const uhd::stream_args_t &args);      bool recv_async_msg(uhd::async_metadata_t &, double); +    static uhd::usrp::mboard_eeprom_t get_mb_eeprom(usrp2_iface &); +  private:      struct mb_container_type{          usrp2_iface::sptr iface; diff --git a/host/lib/usrp/x300/CMakeLists.txt b/host/lib/usrp/x300/CMakeLists.txt index 5f8e83e1c..3a48c9900 100644 --- a/host/lib/usrp/x300/CMakeLists.txt +++ b/host/lib/usrp/x300/CMakeLists.txt @@ -34,6 +34,7 @@ IF(ENABLE_X300)          ${CMAKE_CURRENT_SOURCE_DIR}/x300_dboard_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/x300_clock_ctrl.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/x300_image_loader.cpp +        ${CMAKE_CURRENT_SOURCE_DIR}/x300_mb_eeprom_iface.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/x300_mb_eeprom.cpp          ${CMAKE_CURRENT_SOURCE_DIR}/cdecode.c      ) diff --git a/host/lib/usrp/x300/x300_impl.cpp b/host/lib/usrp/x300/x300_impl.cpp index 1e22f7fb7..f98bdb5b1 100644 --- a/host/lib/usrp/x300/x300_impl.cpp +++ b/host/lib/usrp/x300/x300_impl.cpp @@ -18,7 +18,7 @@  #include "x300_impl.hpp"  #include "x300_lvbitx.hpp"  #include "x310_lvbitx.hpp" -#include "x300_mb_eeprom.hpp" +#include "x300_mb_eeprom_iface.hpp"  #include "apply_corrections.hpp"  #include <boost/algorithm/string.hpp>  #include <boost/asio.hpp> @@ -125,7 +125,8 @@ static device_addrs_t x300_find_with_addr(const device_addr_t &hint)              i2c_core_100_wb32::sptr zpu_i2c = i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE);              x300_mb_eeprom_iface::sptr eeprom_iface = x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c); -            const mboard_eeprom_t mb_eeprom(*eeprom_iface, "X300"); +            const mboard_eeprom_t mb_eeprom = +                x300_impl::get_mb_eeprom(eeprom_iface);              if (mb_eeprom.size() == 0 or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER)              {                  // Skip device claimed by another process @@ -233,7 +234,8 @@ static device_addrs_t x300_find_pcie(const device_addr_t &hint, bool explicit_qu              i2c_core_100_wb32::sptr zpu_i2c = i2c_core_100_wb32::make(zpu_ctrl, I2C1_BASE);              x300_mb_eeprom_iface::sptr eeprom_iface = x300_mb_eeprom_iface::make(zpu_ctrl, zpu_i2c); -            const mboard_eeprom_t mb_eeprom(*eeprom_iface, "X300"); +            const mboard_eeprom_t mb_eeprom = +                x300_impl::get_mb_eeprom(eeprom_iface);              if (mb_eeprom.size() == 0 or x300_impl::claim_status(zpu_ctrl) == x300_impl::CLAIMED_BY_OTHER)              {                  // Skip device claimed by another process @@ -783,13 +785,21 @@ void x300_impl::setup_mb(const size_t mb_i, const uhd::device_addr_t &dev_addr)      x300_mb_eeprom_iface::sptr eeprom16 = x300_mb_eeprom_iface::make(mb.zpu_ctrl, mb.zpu_i2c);      if (dev_addr.has_key("blank_eeprom"))      { -        UHD_LOGGER_WARNING("X300") << "Obliterating the motherboard EEPROM..." ; +        UHD_LOGGER_WARNING("X300") << "Obliterating the motherboard EEPROM...";          eeprom16->write_eeprom(0x50, 0, byte_vector_t(256, 0xff));      } -    const mboard_eeprom_t mb_eeprom(*eeprom16, "X300"); + +    const mboard_eeprom_t mb_eeprom = get_mb_eeprom(eeprom16);      _tree->create<mboard_eeprom_t>(mb_path / "eeprom") +        // Initialize the property with a current copy of the EEPROM contents          .set(mb_eeprom) -        .add_coerced_subscriber(boost::bind(&x300_impl::set_mb_eeprom, this, mb.zpu_i2c, _1)); +        // Whenever this property is written, update the chip +        .add_coerced_subscriber( +            [this, eeprom16](const mboard_eeprom_t &mb_eeprom){ +                this->set_mb_eeprom(eeprom16, mb_eeprom); +            } +        ) +    ;      bool recover_mb_eeprom = dev_addr.has_key("recover_mb_eeprom");      if (recover_mb_eeprom) { @@ -1524,16 +1534,6 @@ bool x300_impl::is_pps_present(mboard_members_t& mb)  }  /*********************************************************************** - * eeprom - **********************************************************************/ - -void x300_impl::set_mb_eeprom(i2c_iface::sptr i2c, const mboard_eeprom_t &mb_eeprom) -{ -    i2c_iface::sptr eeprom16 = i2c->eeprom16(); -    mb_eeprom.commit(*eeprom16, "X300"); -} - -/***********************************************************************   * claimer logic   **********************************************************************/ diff --git a/host/lib/usrp/x300/x300_impl.hpp b/host/lib/usrp/x300/x300_impl.hpp index 7186e5f4f..a1ff65a5c 100644 --- a/host/lib/usrp/x300/x300_impl.hpp +++ b/host/lib/usrp/x300/x300_impl.hpp @@ -147,6 +147,9 @@ public:      static x300_mboard_t get_mb_type_from_pcie(const std::string& resource, const std::string& rpc_port);      static x300_mboard_t get_mb_type_from_eeprom(const uhd::usrp::mboard_eeprom_t& mb_eeprom); +    //! Read out the on-board EEPROM, convert to dict, and return +    static uhd::usrp::mboard_eeprom_t get_mb_eeprom(uhd::i2c_iface::sptr i2c); +  protected:      void subdev_to_blockid(              const uhd::usrp::subdev_spec_pair_t &spec, const size_t mb_i, @@ -287,7 +290,11 @@ private:      bool wait_for_clk_locked(mboard_members_t& mb, uint32_t which, double timeout);      bool is_pps_present(mboard_members_t& mb); -    void set_mb_eeprom(uhd::i2c_iface::sptr i2c, const uhd::usrp::mboard_eeprom_t &); +    //! Write the contents of an EEPROM dict to the on-board EEPROM +    void set_mb_eeprom( +            uhd::i2c_iface::sptr i2c, +            const uhd::usrp::mboard_eeprom_t & +    );      void check_fw_compat(const uhd::fs_path &mb_path, uhd::wb_iface::sptr iface);      void check_fpga_compat(const uhd::fs_path &mb_path, const mboard_members_t &members); diff --git a/host/lib/usrp/x300/x300_mb_eeprom.cpp b/host/lib/usrp/x300/x300_mb_eeprom.cpp index 084685991..da4cf6021 100644 --- a/host/lib/usrp/x300/x300_mb_eeprom.cpp +++ b/host/lib/usrp/x300/x300_mb_eeprom.cpp @@ -1,190 +1,198 @@  // -// Copyright 2013-2016 Ettus Research LLC +// Copyright 2017 Ettus Research (National Instruments Corp.)  // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// SPDX-License-Identifier: GPL-3.0  // -/* - * x300_mb_eeprom_iface - * This interface was created to prevent MB EEPROM corruption while reading - * data during discovery.  For devices with firmware version newer than 5.0, - * the EEPROM data is read into firmware memory and available without - * claiming the device.  For devices with firmware versions 5.0 and older, - * the code makes sure to claim the device before driving the I2C bus.  This - * has the unfortunate side effect of preventing multiple processes from - * discovering the device simultaneously, but is far better than having EEPROM - * corruption. - */ - -#include "x300_mb_eeprom.hpp" -#include "x300_fw_common.h" -#include "x300_regs.hpp"  #include "x300_impl.hpp" -#include <uhd/exception.hpp> -#include <uhd/utils/platform.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/utils/byteswap.hpp> -#include <boost/thread.hpp> +#include "eeprom_utils.hpp" +#include <uhd/usrp/mboard_eeprom.hpp> +#include <uhd/types/serial.hpp> -using namespace uhd; +namespace { +    const uint8_t X300_EEPROM_ADDR = 0x50; + +    struct x300_eeprom_map +    { +        //identifying numbers +        unsigned char revision[2]; +        unsigned char product[2]; +        unsigned char revision_compat[2]; +        uint8_t _pad0[2]; + +        //all the mac addrs +        uint8_t mac_addr0[6]; +        uint8_t _pad1[2]; +        uint8_t mac_addr1[6]; +        uint8_t _pad2[2]; + +        //all the IP addrs +        uint32_t gateway; +        uint32_t subnet[4]; +        uint32_t ip_addr[4]; +        uint8_t _pad3[16]; + +        //names and serials +        unsigned char name[NAME_MAX_LEN]; +        unsigned char serial[SERIAL_LEN]; +    }; +} -static const uint32_t X300_FW_SHMEM_IDENT_MIN_VERSION = 0x50001; +using namespace uhd; +using uhd::usrp::mboard_eeprom_t; -class x300_mb_eeprom_iface_impl : public x300_mb_eeprom_iface +mboard_eeprom_t x300_impl::get_mb_eeprom(uhd::i2c_iface::sptr iface)  { -public: +    byte_vector_t bytes = +        iface->read_eeprom(X300_EEPROM_ADDR, 0, sizeof(struct x300_eeprom_map)); -    x300_mb_eeprom_iface_impl(wb_iface::sptr wb, i2c_iface::sptr i2c) : _wb(wb), _i2c(i2c) -    { -        _compat_num = _wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_COMPAT_NUM)); +    mboard_eeprom_t mb_eeprom; +    if (bytes.empty()) { +        return mb_eeprom;      } -    ~x300_mb_eeprom_iface_impl() +    //extract the revision number +    mb_eeprom["revision"] = uint16_bytes_to_string( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, revision), +            bytes.begin() + (offsetof(x300_eeprom_map, revision)+2)) +    ); + +    //extract the revision compat number +    mb_eeprom["revision_compat"] = uint16_bytes_to_string( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, revision_compat), +            bytes.begin() + (offsetof(x300_eeprom_map, revision_compat)+2)) +    ); + +    //extract the product code +    mb_eeprom["product"] = uint16_bytes_to_string( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, product), +            bytes.begin() + (offsetof(x300_eeprom_map, product)+2)) +    ); + +    //extract the mac addresses +    mb_eeprom["mac-addr0"] = mac_addr_t::from_bytes( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, mac_addr0), +            bytes.begin() + (offsetof(x300_eeprom_map, mac_addr0)+6)) +    ).to_string(); +    mb_eeprom["mac-addr1"] = mac_addr_t::from_bytes( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, mac_addr1), +            bytes.begin() + (offsetof(x300_eeprom_map, mac_addr1)+6)) +    ).to_string(); + +    //extract the ip addresses +    boost::asio::ip::address_v4::bytes_type ip_addr_bytes; +    byte_copy( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, gateway), +            bytes.begin() + (offsetof(x300_eeprom_map, gateway)+4)), +            ip_addr_bytes +    ); +    mb_eeprom["gateway"] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); +    for (size_t i = 0; i < 4; i++)      { -        /* NOP */ +        const std::string n(1, i+'0'); +        byte_copy( +                byte_vector_t( +                bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)), +                bytes.begin() + (offsetof(x300_eeprom_map, ip_addr)+(i*4)+4)), +                ip_addr_bytes +        ); +        mb_eeprom["ip-addr"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string(); + +        byte_copy( +                byte_vector_t( +                bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)), +                bytes.begin() + (offsetof(x300_eeprom_map, subnet)+(i*4)+4)), +                ip_addr_bytes +        ); +        mb_eeprom["subnet"+n] = boost::asio::ip::address_v4(ip_addr_bytes).to_string();      } -    /*! -     * Write bytes over the i2c. -     * \param addr the address -     * \param buf the vector of bytes -     */ -    void write_i2c( -        uint16_t addr, -        const byte_vector_t &buf -    ) -    { -        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); -        if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) -        { -            throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); -        } -        _i2c->write_i2c(addr, buf); -    } +    //extract the serial +    mb_eeprom["serial"] = bytes_to_string( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, serial), +            bytes.begin() + (offsetof(x300_eeprom_map, serial)+SERIAL_LEN)) +    ); + +    //extract the name +    mb_eeprom["name"] = bytes_to_string( +            byte_vector_t( +            bytes.begin() + offsetof(x300_eeprom_map, name), +            bytes.begin() + (offsetof(x300_eeprom_map, name)+NAME_MAX_LEN)) +    ); + +    return mb_eeprom; +} -    /*! -     * Read bytes over the i2c. -     * \param addr the address -     * \param num_bytes number of bytes to read -     * \return a vector of bytes -     */ -    byte_vector_t read_i2c( -        uint16_t addr, -        size_t num_bytes -    ) -    { -        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); -        byte_vector_t bytes; -        if (_compat_num > X300_FW_SHMEM_IDENT_MIN_VERSION) -        { -            bytes = read_eeprom(addr, 0, num_bytes); -        } else { -            x300_impl::claim_status_t status = x300_impl::claim_status(_wb); -            // Claim device before driving the I2C bus -            if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) -            { -                bytes = _i2c->read_i2c(addr, num_bytes); -                if (status != x300_impl::CLAIMED_BY_US) -                { -                    // We didn't originally have the claim, so give it up -                    x300_impl::release(_wb); -                } -            } -        } -        return bytes; -    } -    /*! -     * Write bytes to an eeprom. -     * \param addr the address -     * \param offset byte offset -     * \param buf the vector of bytes -     */ -    void write_eeprom( -        uint16_t addr, -        uint16_t offset, -        const byte_vector_t &buf -    ) +void x300_impl::set_mb_eeprom( +        i2c_iface::sptr iface, +        const mboard_eeprom_t &mb_eeprom +) { +    //parse the revision number +    if (mb_eeprom.has_key("revision")) iface->write_eeprom( +        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision), +        string_to_uint16_bytes(mb_eeprom["revision"]) +    ); + +    //parse the revision compat number +    if (mb_eeprom.has_key("revision_compat")) iface->write_eeprom( +        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, revision_compat), +        string_to_uint16_bytes(mb_eeprom["revision_compat"]) +    ); + +    //parse the product code +    if (mb_eeprom.has_key("product")) iface->write_eeprom( +        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, product), +        string_to_uint16_bytes(mb_eeprom["product"]) +    ); + +    //store the mac addresses +    if (mb_eeprom.has_key("mac-addr0")) iface->write_eeprom( +        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr0), +        mac_addr_t::from_string(mb_eeprom["mac-addr0"]).to_bytes() +    ); +    if (mb_eeprom.has_key("mac-addr1")) iface->write_eeprom( +        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, mac_addr1), +        mac_addr_t::from_string(mb_eeprom["mac-addr1"]).to_bytes() +    ); + +    //store the ip addresses +    byte_vector_t ip_addr_bytes(4); +    if (mb_eeprom.has_key("gateway")){ +        byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["gateway"]).to_bytes(), ip_addr_bytes); +        iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, gateway), ip_addr_bytes); +    } +    for (size_t i = 0; i < 4; i++)      { -        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); -        if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) -        { -            throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); +        const std::string n(1, i+'0'); +        if (mb_eeprom.has_key("ip-addr"+n)){ +            byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["ip-addr"+n]).to_bytes(), ip_addr_bytes); +            iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, ip_addr)+(i*4), ip_addr_bytes);          } -        _i2c->write_eeprom(addr, offset, buf); -    } -    /*! -     * Read bytes from an eeprom. -     * \param addr the address -     * \param offset byte offset -     * \param num_bytes number of bytes to read -     * \return a vector of bytes -     */ -    byte_vector_t read_eeprom( -        uint16_t addr, -        uint16_t offset, -        size_t num_bytes -    ) -    { -        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); -        byte_vector_t bytes; -        x300_impl::claim_status_t status = x300_impl::claim_status(_wb); -        if (_compat_num >= X300_FW_SHMEM_IDENT_MIN_VERSION) -        { -            // Get MB EEPROM data from firmware memory -            if (num_bytes == 0) return bytes; - -            size_t bytes_read = 0; -            for (size_t word = offset / 4; bytes_read < num_bytes; word++) -            { -                uint32_t value = byteswap(_wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_IDENT + word))); -                for (size_t byte = offset % 4; byte < 4 and bytes_read < num_bytes; byte++) -                { -                    bytes.push_back(uint8_t((value >> (byte * 8)) & 0xff)); -                    bytes_read++; -                } -            } -        } else { -            // Claim device before driving the I2C bus -            if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) -            { -                bytes = _i2c->read_eeprom(addr, offset, num_bytes); -                if (status != x300_impl::CLAIMED_BY_US) -                { -                    // We didn't originally have the claim, so give it up -                    x300_impl::release(_wb); -                } -            } +        if (mb_eeprom.has_key("subnet"+n)){ +            byte_copy(boost::asio::ip::address_v4::from_string(mb_eeprom["subnet"+n]).to_bytes(), ip_addr_bytes); +            iface->write_eeprom(X300_EEPROM_ADDR, offsetof(x300_eeprom_map, subnet)+(i*4), ip_addr_bytes);          } -        return bytes;      } - -private: -    wb_iface::sptr _wb; -    i2c_iface::sptr _i2c; -    uint32_t _compat_num; -}; - -x300_mb_eeprom_iface::~x300_mb_eeprom_iface(void) -{ -    /* NOP */ -} - -x300_mb_eeprom_iface::sptr x300_mb_eeprom_iface::make(wb_iface::sptr wb, i2c_iface::sptr i2c) -{ -    return boost::make_shared<x300_mb_eeprom_iface_impl>(wb, i2c->eeprom16()); +    //store the serial +    if (mb_eeprom.has_key("serial")) iface->write_eeprom( +        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, serial), +        string_to_bytes(mb_eeprom["serial"], SERIAL_LEN) +    ); + +    //store the name +    if (mb_eeprom.has_key("name")) iface->write_eeprom( +        X300_EEPROM_ADDR, offsetof(x300_eeprom_map, name), +        string_to_bytes(mb_eeprom["name"], NAME_MAX_LEN) +    );  } diff --git a/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp b/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp new file mode 100644 index 000000000..adc766c39 --- /dev/null +++ b/host/lib/usrp/x300/x300_mb_eeprom_iface.cpp @@ -0,0 +1,190 @@ +// +// Copyright 2013-2016 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 +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +/* + * x300_mb_eeprom_iface + * This interface was created to prevent MB EEPROM corruption while reading + * data during discovery.  For devices with firmware version newer than 5.0, + * the EEPROM data is read into firmware memory and available without + * claiming the device.  For devices with firmware versions 5.0 and older, + * the code makes sure to claim the device before driving the I2C bus.  This + * has the unfortunate side effect of preventing multiple processes from + * discovering the device simultaneously, but is far better than having EEPROM + * corruption. + */ + +#include "x300_mb_eeprom_iface.hpp" +#include "x300_fw_common.h" +#include "x300_regs.hpp" +#include "x300_impl.hpp" +#include <uhd/exception.hpp> +#include <uhd/utils/platform.hpp> +#include <uhd/utils/log.hpp> +#include <uhd/utils/byteswap.hpp> +#include <boost/thread.hpp> + +using namespace uhd; + +static const uint32_t X300_FW_SHMEM_IDENT_MIN_VERSION = 0x50001; + +class x300_mb_eeprom_iface_impl : public x300_mb_eeprom_iface +{ +public: + +    x300_mb_eeprom_iface_impl(wb_iface::sptr wb, i2c_iface::sptr i2c) : _wb(wb), _i2c(i2c) +    { +        _compat_num = _wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_COMPAT_NUM)); +    } + +    ~x300_mb_eeprom_iface_impl() +    { +        /* NOP */ +    } + +    /*! +     * Write bytes over the i2c. +     * \param addr the address +     * \param buf the vector of bytes +     */ +    void write_i2c( +        uint16_t addr, +        const byte_vector_t &buf +    ) +    { +        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); +        if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) +        { +            throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); +        } +        _i2c->write_i2c(addr, buf); +    } + +    /*! +     * Read bytes over the i2c. +     * \param addr the address +     * \param num_bytes number of bytes to read +     * \return a vector of bytes +     */ +    byte_vector_t read_i2c( +        uint16_t addr, +        size_t num_bytes +    ) +    { +        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); +        byte_vector_t bytes; +        if (_compat_num > X300_FW_SHMEM_IDENT_MIN_VERSION) +        { +            bytes = read_eeprom(addr, 0, num_bytes); +        } else { +            x300_impl::claim_status_t status = x300_impl::claim_status(_wb); +            // Claim device before driving the I2C bus +            if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) +            { +                bytes = _i2c->read_i2c(addr, num_bytes); +                if (status != x300_impl::CLAIMED_BY_US) +                { +                    // We didn't originally have the claim, so give it up +                    x300_impl::release(_wb); +                } +            } +        } +        return bytes; +    } + +    /*! +     * Write bytes to an eeprom. +     * \param addr the address +     * \param offset byte offset +     * \param buf the vector of bytes +     */ +    void write_eeprom( +        uint16_t addr, +        uint16_t offset, +        const byte_vector_t &buf +    ) +    { +        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); +        if (x300_impl::claim_status(_wb) != x300_impl::CLAIMED_BY_US) +        { +            throw uhd::io_error("Attempted to write MB EEPROM without claim to device."); +        } +        _i2c->write_eeprom(addr, offset, buf); +    } + +    /*! +     * Read bytes from an eeprom. +     * \param addr the address +     * \param offset byte offset +     * \param num_bytes number of bytes to read +     * \return a vector of bytes +     */ +    byte_vector_t read_eeprom( +        uint16_t addr, +        uint16_t offset, +        size_t num_bytes +    ) +    { +        UHD_ASSERT_THROW(addr == MBOARD_EEPROM_ADDR); +        byte_vector_t bytes; +        x300_impl::claim_status_t status = x300_impl::claim_status(_wb); +        if (_compat_num >= X300_FW_SHMEM_IDENT_MIN_VERSION) +        { +            // Get MB EEPROM data from firmware memory +            if (num_bytes == 0) return bytes; + +            size_t bytes_read = 0; +            for (size_t word = offset / 4; bytes_read < num_bytes; word++) +            { +                uint32_t value = byteswap(_wb->peek32(X300_FW_SHMEM_ADDR(X300_FW_SHMEM_IDENT + word))); +                for (size_t byte = offset % 4; byte < 4 and bytes_read < num_bytes; byte++) +                { +                    bytes.push_back(uint8_t((value >> (byte * 8)) & 0xff)); +                    bytes_read++; +                } +            } +        } else { +            // Claim device before driving the I2C bus +            if (status == x300_impl::CLAIMED_BY_US or x300_impl::try_to_claim(_wb)) +            { +                bytes = _i2c->read_eeprom(addr, offset, num_bytes); +                if (status != x300_impl::CLAIMED_BY_US) +                { +                    // We didn't originally have the claim, so give it up +                    x300_impl::release(_wb); +                } +            } +        } +        return bytes; +    } + + +private: +    wb_iface::sptr _wb; +    i2c_iface::sptr _i2c; +    uint32_t _compat_num; +}; + +x300_mb_eeprom_iface::~x300_mb_eeprom_iface(void) +{ +    /* NOP */ +} + +x300_mb_eeprom_iface::sptr x300_mb_eeprom_iface::make(wb_iface::sptr wb, i2c_iface::sptr i2c) +{ +    return boost::make_shared<x300_mb_eeprom_iface_impl>(wb, i2c->eeprom16()); +} + diff --git a/host/lib/usrp/x300/x300_mb_eeprom.hpp b/host/lib/usrp/x300/x300_mb_eeprom_iface.hpp index 0649855c6..0649855c6 100644 --- a/host/lib/usrp/x300/x300_mb_eeprom.hpp +++ b/host/lib/usrp/x300/x300_mb_eeprom_iface.hpp diff --git a/host/lib/utils/CMakeLists.txt b/host/lib/utils/CMakeLists.txt index 0b163c35f..a9e3ae89a 100644 --- a/host/lib/utils/CMakeLists.txt +++ b/host/lib/utils/CMakeLists.txt @@ -19,6 +19,8 @@  # This file included, use CMake directory variables  ######################################################################## +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +  ########################################################################  # Setup defines for process scheduling  ######################################################################## @@ -168,6 +170,7 @@ SET_SOURCE_FILES_PROPERTIES(  ########################################################################  LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/csv.cpp +    ${CMAKE_CURRENT_SOURCE_DIR}/eeprom_utils.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/gain_group.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/ihex.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/load_modules.cpp diff --git a/host/lib/utils/eeprom_utils.cpp b/host/lib/utils/eeprom_utils.cpp new file mode 100644 index 000000000..acf81a1ce --- /dev/null +++ b/host/lib/utils/eeprom_utils.cpp @@ -0,0 +1,22 @@ +// +// Copyright 2017 Ettus Research (National Instruments Corp.) +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include "eeprom_utils.hpp" +#include <boost/lexical_cast.hpp> + +uhd::byte_vector_t string_to_uint16_bytes(const std::string &num_str){ +    const uint16_t num = boost::lexical_cast<uint16_t>(num_str); +    const std::vector<uint8_t> lsb_msb = { +        uint8_t(num >> 0), +        uint8_t(num >> 8) +    }; +    return lsb_msb; +} + +std::string uint16_bytes_to_string(const uhd::byte_vector_t &bytes){ +    const uint16_t num = (uint16_t(bytes.at(0)) << 0) | (uint16_t(bytes.at(1)) << 8); +    return (num == 0 or num == 0xffff)? "" : std::to_string(num); +} diff --git a/host/lib/utils/eeprom_utils.hpp b/host/lib/utils/eeprom_utils.hpp new file mode 100644 index 000000000..b6ff264fb --- /dev/null +++ b/host/lib/utils/eeprom_utils.hpp @@ -0,0 +1,20 @@ +// +// Copyright 2017 Ettus Research (National Instruments Corp.) +// +// SPDX-License-Identifier: GPL-3.0 +// + +#include <uhd/types/byte_vector.hpp> +#include <uhd/types/mac_addr.hpp> +#include <boost/asio/ip/address_v4.hpp> +#include <string> +#include <vector> + +static const size_t SERIAL_LEN = 9; +static const size_t NAME_MAX_LEN = 32 - SERIAL_LEN; + +//! convert a string to a byte vector to write to eeprom +uhd::byte_vector_t string_to_uint16_bytes(const std::string &num_str); + +//! convert a byte vector read from eeprom to a string +std::string uint16_bytes_to_string(const uhd::byte_vector_t &bytes);  | 
