// // Copyright 2017-18 Ettus Research (National Instruments Corp.) // // SPDX-License-Identifier: GPL-3.0-or-later // #include "x300_impl.hpp" #include #include #include 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]; }; } // namespace using namespace uhd; using uhd::usrp::mboard_eeprom_t; mboard_eeprom_t x300_impl::get_mb_eeprom(uhd::i2c_iface::sptr iface) { byte_vector_t bytes = iface->read_eeprom(X300_EEPROM_ADDR, 0, sizeof(struct x300_eeprom_map)); mboard_eeprom_t mb_eeprom; if (bytes.empty()) { return mb_eeprom; } // 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, char(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))); return mb_eeprom; } void x300_impl::set_mb_eeprom(i2c_iface::sptr iface, const mboard_eeprom_t& mb_eeprom) { const mboard_eeprom_t curr_eeprom = get_mb_eeprom(iface); // Check for duplicate MAC and IP addresses const std::vector mac_keys{"mac-addr0", "mac-addr1"}; const std::vector ip_keys{ "ip-addr0", "ip-addr1", "ip-addr2", "ip-addr3"}; // make sure there are no duplicate values if (check_for_duplicates( "X300", mb_eeprom, curr_eeprom, "MAC address", mac_keys) or check_for_duplicates( "X300", mb_eeprom, curr_eeprom, "IP address", ip_keys)) { throw uhd::value_error( "Duplicate values not permitted - write to EEPROM aborted"); } // 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, char(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)); }