// // 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]; }; } 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) ); }