aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/usrp/n230/n230_eeprom_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/usrp/n230/n230_eeprom_manager.cpp')
-rw-r--r--host/lib/usrp/n230/n230_eeprom_manager.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/host/lib/usrp/n230/n230_eeprom_manager.cpp b/host/lib/usrp/n230/n230_eeprom_manager.cpp
new file mode 100644
index 000000000..b19deb23a
--- /dev/null
+++ b/host/lib/usrp/n230/n230_eeprom_manager.cpp
@@ -0,0 +1,207 @@
+//
+// Copyright 2013-2014,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/>.
+//
+
+#include "n230_eeprom.h"
+#include <uhd/utils/byteswap.hpp>
+#include <uhd/utils/msg.hpp>
+#include <uhd/exception.hpp>
+#include <uhd/types/mac_addr.hpp>
+#include <boost/format.hpp>
+#include <boost/asio.hpp> //used for htonl and ntohl
+#include "n230_eeprom_manager.hpp"
+
+namespace uhd { namespace usrp { namespace n230 {
+
+const double n230_eeprom_manager::UDP_TIMEOUT_IN_SEC = 2.0;
+
+n230_eeprom_manager::n230_eeprom_manager(const std::string& addr):
+ _seq_num(0)
+{
+ _udp_xport = transport::udp_simple::make_connected(
+ addr, BOOST_STRINGIZE(N230_FW_COMMS_FLASH_PROG_PORT));
+ read_mb_eeprom();
+}
+
+static const std::string _bytes_to_string(const uint8_t* bytes, size_t max_len)
+{
+ std::string out;
+ for (size_t i = 0; i < max_len; i++) {
+ if (bytes[i] < 32 or bytes[i] > 127) return out;
+ out += bytes[i];
+ }
+ return out;
+}
+
+static void _string_to_bytes(const std::string &string, size_t max_len, uint8_t* buffer)
+{
+ byte_vector_t bytes;
+ const size_t len = std::min(string.size(), max_len);
+ for (size_t i = 0; i < len; i++){
+ buffer[i] = string[i];
+ }
+ if (len < max_len - 1) buffer[len] = '\0';
+}
+
+const mboard_eeprom_t& n230_eeprom_manager::read_mb_eeprom()
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ //Read EEPROM from device
+ _transact(N230_FLASH_COMM_CMD_READ_NV_DATA);
+ const n230_eeprom_map_t* map_ptr = reinterpret_cast<const n230_eeprom_map_t*>(_response.data);
+ const n230_eeprom_map_t& map = *map_ptr;
+
+ uint16_t ver_major = uhd::htonx<boost::uint16_t>(map.data_version_major);
+ uint16_t ver_minor = uhd::htonx<boost::uint16_t>(map.data_version_minor);
+
+ _mb_eeprom["product"] = boost::lexical_cast<std::string>(
+ uhd::htonx<boost::uint16_t>(map.hw_product));
+ _mb_eeprom["revision"] = boost::lexical_cast<std::string>(
+ uhd::htonx<boost::uint16_t>(map.hw_revision));
+ //The revision_compat field does not exist in version 1.0
+ //EEPROM version 1.0 will only exist on HW revision 1 so it is safe to set
+ //revision_compat = revision
+ if (ver_major == 1 and ver_minor == 0) {
+ _mb_eeprom["revision_compat"] = _mb_eeprom["revision"];
+ } else {
+ _mb_eeprom["revision_compat"] = boost::lexical_cast<std::string>(
+ uhd::htonx<boost::uint16_t>(map.hw_revision_compat));
+ }
+ _mb_eeprom["serial"] = _bytes_to_string(
+ map.serial, N230_EEPROM_SERIAL_LEN);
+
+ //Extract ethernet info
+ _mb_eeprom["gateway"] = boost::asio::ip::address_v4(
+ uhd::htonx<boost::uint32_t>(map.gateway)).to_string();
+ for (size_t i = 0; i < N230_MAX_NUM_ETH_PORTS; i++) {
+ const std::string n(1, i+'0');
+ _mb_eeprom["ip-addr"+n] = boost::asio::ip::address_v4(
+ uhd::htonx<boost::uint32_t>(map.eth_info[i].ip_addr)).to_string();
+ _mb_eeprom["subnet"+n] = boost::asio::ip::address_v4(
+ uhd::htonx<boost::uint32_t>(map.eth_info[i].subnet)).to_string();
+ byte_vector_t mac_addr(map.eth_info[i].mac_addr, map.eth_info[i].mac_addr + 6);
+ _mb_eeprom["mac-addr"+n] = mac_addr_t::from_bytes(mac_addr).to_string();
+ }
+
+ _mb_eeprom["name"] = _bytes_to_string(
+ map.user_name, N230_EEPROM_NAME_LEN);
+
+ return _mb_eeprom;
+}
+
+void n230_eeprom_manager::write_mb_eeprom(const mboard_eeprom_t& eeprom)
+{
+ boost::mutex::scoped_lock lock(_mutex);
+
+ _mb_eeprom = eeprom;
+
+ n230_eeprom_map_t* map_ptr = reinterpret_cast<n230_eeprom_map_t*>(_request.data);
+ memset(map_ptr, 0xff, sizeof(n230_eeprom_map_t)); //Initialize to erased state
+ //Read EEPROM from device
+ _transact(N230_FLASH_COMM_CMD_READ_NV_DATA);
+ memcpy(map_ptr, _response.data, sizeof(n230_eeprom_map_t));
+ n230_eeprom_map_t& map = *map_ptr;
+
+ // Automatic version upgrade handling
+ uint16_t old_ver_major = uhd::htonx<boost::uint16_t>(map.data_version_major);
+ uint16_t old_ver_minor = uhd::htonx<boost::uint16_t>(map.data_version_minor);
+
+ //The revision_compat field does not exist for version 1.0 so force write it
+ //EEPROM version 1.0 will only exist on HW revision 1 so it is safe to set
+ //revision_compat = revision for the upgrade
+ bool force_write_version_compat = (old_ver_major == 1 and old_ver_minor == 0);
+
+ map.data_version_major = uhd::htonx<boost::uint16_t>(N230_EEPROM_VER_MAJOR);
+ map.data_version_minor = uhd::htonx<boost::uint16_t>(N230_EEPROM_VER_MINOR);
+
+ if (_mb_eeprom.has_key("product")) {
+ map.hw_product = uhd::htonx<boost::uint16_t>(
+ boost::lexical_cast<boost::uint16_t>(_mb_eeprom["product"]));
+ }
+ if (_mb_eeprom.has_key("revision")) {
+ map.hw_revision = uhd::htonx<boost::uint16_t>(
+ boost::lexical_cast<boost::uint16_t>(_mb_eeprom["revision"]));
+ }
+ if (_mb_eeprom.has_key("revision_compat")) {
+ map.hw_revision_compat = uhd::htonx<boost::uint16_t>(
+ boost::lexical_cast<boost::uint16_t>(_mb_eeprom["revision_compat"]));
+ } else if (force_write_version_compat) {
+ map.hw_revision_compat = map.hw_revision;
+ }
+ if (_mb_eeprom.has_key("serial")) {
+ _string_to_bytes(_mb_eeprom["serial"], N230_EEPROM_SERIAL_LEN, map.serial);
+ }
+
+ //Push ethernet info
+ if (_mb_eeprom.has_key("gateway")){
+ map.gateway = uhd::htonx<boost::uint32_t>(
+ boost::asio::ip::address_v4::from_string(_mb_eeprom["gateway"]).to_ulong());
+ }
+ for (size_t i = 0; i < N230_MAX_NUM_ETH_PORTS; i++) {
+ const std::string n(1, i+'0');
+ if (_mb_eeprom.has_key("ip-addr"+n)){
+ map.eth_info[i].ip_addr = uhd::htonx<boost::uint32_t>(
+ boost::asio::ip::address_v4::from_string(_mb_eeprom["ip-addr"+n]).to_ulong());
+ }
+ if (_mb_eeprom.has_key("subnet"+n)){
+ map.eth_info[i].subnet = uhd::htonx<boost::uint32_t>(
+ boost::asio::ip::address_v4::from_string(_mb_eeprom["subnet"+n]).to_ulong());
+ }
+ if (_mb_eeprom.has_key("mac-addr"+n)) {
+ byte_vector_t mac_addr = mac_addr_t::from_string(_mb_eeprom["mac-addr"+n]).to_bytes();
+ std::copy(mac_addr.begin(), mac_addr.end(), map.eth_info[i].mac_addr);
+ }
+ }
+ //store the name
+ if (_mb_eeprom.has_key("name")) {
+ _string_to_bytes(_mb_eeprom["name"], N230_EEPROM_NAME_LEN, map.user_name);
+ }
+
+ //Write EEPROM to device
+ _transact(N230_FLASH_COMM_CMD_WRITE_NV_DATA);
+}
+
+void n230_eeprom_manager::_transact(const boost::uint32_t command)
+{
+ //Load request struct
+ _request.flags = uhd::htonx<boost::uint32_t>(N230_FLASH_COMM_FLAGS_ACK | command);
+ _request.seq = uhd::htonx<boost::uint32_t>(_seq_num++);
+
+ //Send request
+ _flush_xport();
+ _udp_xport->send(boost::asio::buffer(&_request, sizeof(_request)));
+
+ //Recv reply
+ const size_t nbytes = _udp_xport->recv(boost::asio::buffer(&_response, sizeof(_response)), UDP_TIMEOUT_IN_SEC);
+ if (nbytes == 0) throw uhd::io_error("n230_eeprom_manager::_transact failure");
+
+ //Sanity checks
+ const size_t flags = uhd::ntohx<boost::uint32_t>(_response.flags);
+ UHD_ASSERT_THROW(nbytes == sizeof(_response));
+ UHD_ASSERT_THROW(_response.seq == _request.seq);
+ UHD_ASSERT_THROW(flags & command);
+}
+
+void n230_eeprom_manager::_flush_xport()
+{
+ char buff[sizeof(n230_flash_prog_t)] = {};
+ while (_udp_xport->recv(boost::asio::buffer(buff), 0.0)) {
+ /*NOP*/
+ }
+}
+
+}}}; //namespace