aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2017-09-26 18:22:25 -0700
committerMartin Braun <martin.braun@ettus.com>2017-09-29 10:50:56 -0700
commit83dde40090e0bbd91c304602cc0e3c365f7878bb (patch)
treec404968e3d6d35795f331ade6ad3c176f3c1bc8b /host/lib/usrp
parent59736a5bf512db83a6bd7250e14b13c7464770fc (diff)
downloaduhd-83dde40090e0bbd91c304602cc0e3c365f7878bb.tar.gz
uhd-83dde40090e0bbd91c304602cc0e3c365f7878bb.tar.bz2
uhd-83dde40090e0bbd91c304602cc0e3c365f7878bb.zip
uhd: Changed mboard_eeprom_t interface, refactored MB EEPROM code
- uhd::usrp::mboard_eeprom_t is now simply a map. Its commit() method has no utility being a public API call, because the user never gets access to the appropriate I2C object (Minor API breakage) - The central mboard_eeprom.cpp file was broken up and put into many smaller compilation units in every device's implementation folder. - Renamed some of the constants (e.g. B000_* -> USRP1_*, N100_* -> N200_*) - Removed the N000_* EEPROM code, because, well, you know, there's no such device
Diffstat (limited to 'host/lib/usrp')
-rw-r--r--host/lib/usrp/CMakeLists.txt1
-rw-r--r--host/lib/usrp/b100/CMakeLists.txt1
-rw-r--r--host/lib/usrp/b100/b100_impl.cpp9
-rw-r--r--host/lib/usrp/b100/b100_impl.hpp3
-rw-r--r--host/lib/usrp/b100/mb_eeprom.cpp91
-rw-r--r--host/lib/usrp/b200/CMakeLists.txt1
-rw-r--r--host/lib/usrp/b200/b200_image_loader.cpp12
-rw-r--r--host/lib/usrp/b200/b200_impl.cpp9
-rw-r--r--host/lib/usrp/b200/b200_impl.hpp2
-rw-r--r--host/lib/usrp/b200/b200_mb_eeprom.cpp82
-rw-r--r--host/lib/usrp/e100/CMakeLists.txt1
-rw-r--r--host/lib/usrp/e100/e100_impl.cpp14
-rw-r--r--host/lib/usrp/e100/e100_impl.hpp2
-rw-r--r--host/lib/usrp/e100/mb_eeprom.cpp103
-rw-r--r--host/lib/usrp/mboard_eeprom.cpp682
-rw-r--r--host/lib/usrp/usrp1/CMakeLists.txt1
-rw-r--r--host/lib/usrp/usrp1/mb_eeprom.cpp90
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.cpp10
-rw-r--r--host/lib/usrp/usrp1/usrp1_impl.hpp2
-rw-r--r--host/lib/usrp/usrp2/CMakeLists.txt1
-rw-r--r--host/lib/usrp/usrp2/mb_eeprom.cpp175
-rw-r--r--host/lib/usrp/usrp2/usrp2_iface.cpp2
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.cpp7
-rw-r--r--host/lib/usrp/usrp2/usrp2_impl.hpp3
-rw-r--r--host/lib/usrp/x300/CMakeLists.txt1
-rw-r--r--host/lib/usrp/x300/x300_impl.cpp32
-rw-r--r--host/lib/usrp/x300/x300_impl.hpp9
-rw-r--r--host/lib/usrp/x300/x300_mb_eeprom.cpp338
-rw-r--r--host/lib/usrp/x300/x300_mb_eeprom_iface.cpp190
-rw-r--r--host/lib/usrp/x300/x300_mb_eeprom_iface.hpp (renamed from host/lib/usrp/x300/x300_mb_eeprom.hpp)0
30 files changed, 968 insertions, 906 deletions
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